utils.h
Go to the documentation of this file.
00001 /*************************************************************************** 00002 file : $URL: http://svn.code.sf.net/p/frepple/code/trunk/include/frepple/utils.h $ 00003 version : $LastChangedRevision: 1768 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2012-08-28 18:40:42 +0200 (Tue, 28 Aug 2012) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Affero General Public License as Objecthed * 00013 * by the Free Software Foundation; either version 3 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 * 00019 * GNU Affero General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Affero General Public * 00022 * License along with this program. * 00023 * If not, see <http://www.gnu.org/licenses/>. * 00024 * * 00025 ***************************************************************************/ 00026 00027 /** @file utils.h 00028 * @brief Header file for auxilary classes. 00029 * 00030 * @namespace frepple::utils 00031 * @brief Utilities for the frePPle core 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 Visual Studio will complain if system headers are #included both with 00042 and without _DEBUG defined, so we have to #include all the system headers 00043 used by pyconfig.h right here. 00044 */ 00045 #if defined(_DEBUG) && defined(_MSC_VER) 00046 #include <stddef.h> 00047 #include <stdarg.h> 00048 #include <stdio.h> 00049 #include <stdlib.h> 00050 #include <assert.h> 00051 #include <errno.h> 00052 #include <ctype.h> 00053 #include <wchar.h> 00054 #include <basetsd.h> 00055 #include <io.h> 00056 #include <limits.h> 00057 #include <float.h> 00058 #include <string.h> 00059 #include <math.h> 00060 #include <time.h> 00061 #undef _DEBUG 00062 #include "Python.h" 00063 #define _DEBUG 00064 #else 00065 #include "Python.h" 00066 #endif 00067 #include "datetime.h" 00068 00069 // For compatibility with earlier Python releases 00070 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) 00071 typedef int Py_ssize_t; 00072 #define PY_SSIZE_T_MAX INT_MAX 00073 #define PY_SSIZE_T_MIN INT_MIN 00074 #endif 00075 00076 #ifndef DOXYGEN 00077 #include <iostream> 00078 #include <fstream> 00079 #include <sstream> 00080 #include <stdexcept> 00081 #include <ctime> 00082 #include <assert.h> 00083 #include <typeinfo> 00084 #include <float.h> 00085 #endif 00086 00087 // We want to use singly linked lists, but these are not part of the C++ 00088 // standard though. Sigh... 00089 #ifndef DOXYGEN 00090 #ifdef HAVE_EXT_SLIST 00091 // Singly linked lists as extension: gcc 3.x 00092 #include <ext/slist> 00093 using namespace gnu_cxx; 00094 #else 00095 #ifdef HAVE_SLIST 00096 // Singly linked lists available in std stl: gcc 2.95 00097 #include <slist> 00098 #else 00099 // Not available: use a double linked list instead 00100 #define slist list 00101 #endif 00102 #endif 00103 #endif 00104 00105 // STL include files 00106 #ifndef DOXYGEN 00107 #include <list> 00108 #include <map> 00109 #include <set> 00110 #include <string> 00111 #include <stack> 00112 #include <vector> 00113 #include <algorithm> 00114 #endif 00115 using namespace std; 00116 00117 /** @def PACKAGE_VERSION 00118 * Defines the version of frePPLe. 00119 */ 00120 #ifdef HAVE_CONFIG_H 00121 #undef PACKAGE_BUGREPORT 00122 #undef PACKAGE_NAME 00123 #undef PACKAGE_STRING 00124 #undef PACKAGE_TARNAME 00125 #undef PACKAGE_VERSION 00126 #include <config.h> 00127 #else 00128 // Define the version for (windows) compilers that don't use autoconf 00129 #define PACKAGE_VERSION "0.9.2" 00130 #endif 00131 00132 // Header for multithreading 00133 #if defined(MT) 00134 #if defined(HAVE_PTHREAD_H) 00135 #include <pthread.h> 00136 #elif defined(WIN32) 00137 #define WIN32_LEAN_AND_MEAN 00138 #include <windows.h> 00139 #include <process.h> 00140 #else 00141 #error Multithreading not supported on your platform 00142 #endif 00143 #endif 00144 00145 // For the disabled and ansi-challenged people... 00146 #ifndef DOXYGEN 00147 #ifndef HAVE_STRNCASECMP 00148 # ifdef _MSC_VER 00149 # define strncasecmp _strnicmp 00150 # else 00151 # ifdef HAVE_STRNICMP 00152 # define strncasecmp(s1,s2,n) strnicmp(s1,s2,n) 00153 # else 00154 // Last resort. Force it through... 00155 # define strncasecmp(s1,s2,n) strnuppercmp(s1,s2,n) 00156 # endif 00157 # endif 00158 #endif 00159 #endif 00160 00161 /** @def ROUNDING_ERROR 00162 * This constant defines the magnitude of what can still be considered 00163 * as a rounding error. 00164 */ 00165 #define ROUNDING_ERROR 0.000001 00166 00167 // Header files for the Xerces-c XML parser. 00168 #ifndef DOXYGEN 00169 #define XERCES_STATIC_LIBRARY 00170 #include <xercesc/util/PlatformUtils.hpp> 00171 #include <xercesc/sax2/SAX2XMLReader.hpp> 00172 #include <xercesc/sax2/Attributes.hpp> 00173 #include <xercesc/sax2/DefaultHandler.hpp> 00174 #include <xercesc/framework/MemBufInputSource.hpp> 00175 #include <xercesc/sax2/XMLReaderFactory.hpp> 00176 #include <xercesc/util/XMLUni.hpp> 00177 #include <xercesc/framework/MemBufInputSource.hpp> 00178 #include <xercesc/framework/LocalFileInputSource.hpp> 00179 #include <xercesc/framework/StdInInputSource.hpp> 00180 #include <xercesc/framework/URLInputSource.hpp> 00181 #include <xercesc/util/XMLException.hpp> 00182 #endif 00183 00184 /** @def DECLARE_EXPORT 00185 * Used to define which symbols to export from a Windows DLL. 00186 * @def MODULE_EXPORT 00187 * Signature used for a module initialization routine. It assures the 00188 * function is exported appropriately when running on Windows.<br> 00189 * A module will need to define a function with the following prototype: 00190 * @code 00191 * MODULE_EXPORT string initialize(const CommandLoadLibrary::ParameterList&); 00192 * @endcode 00193 */ 00194 #undef DECLARE_EXPORT 00195 #undef MODULE_EXPORT 00196 #if defined(WIN32) && !defined(DOXYGEN) 00197 #ifdef FREPPLE_CORE 00198 #define DECLARE_EXPORT __declspec (dllexport) 00199 #else 00200 #define DECLARE_EXPORT __declspec (dllimport) 00201 #endif 00202 #define MODULE_EXPORT extern "C" __declspec (dllexport) 00203 #else 00204 #define DECLARE_EXPORT 00205 #define MODULE_EXPORT extern "C" 00206 #endif 00207 00208 00209 namespace frepple 00210 { 00211 00212 // Forward declarations 00213 class CommandMoveOperationPlan; 00214 00215 namespace utils 00216 { 00217 00218 // Forward declarations 00219 class Object; 00220 class Keyword; 00221 class XMLInput; 00222 class AttributeList; 00223 00224 // Include the list of predefined tags 00225 #include "frepple/tags.h" 00226 00227 00228 /** This type defines what operation we want to do with the entity. */ 00229 enum Action 00230 { 00231 /** or A.<br> 00232 * Add an new entity, and report an error if the entity already exists. */ 00233 ADD = 0, 00234 /** or C.<br> 00235 * Change an existing entity, and report an error if the entity doesn't 00236 * exist yet. */ 00237 CHANGE = 1, 00238 /** or D.<br> 00239 * Delete an entity, and report an error if the entity doesn't exist. */ 00240 REMOVE = 2, 00241 /** or AC.<br> 00242 * Change an entity or create a new one if it doesn't exist yet.<br> 00243 * This is the default action. 00244 */ 00245 ADD_CHANGE = 3 00246 }; 00247 00248 00249 /** Writes an action description to an output stream. */ 00250 inline ostream & operator << (ostream & os, const Action & d) 00251 { 00252 switch (d) 00253 { 00254 case ADD: os << "ADD"; return os; 00255 case CHANGE: os << "CHANGE"; return os; 00256 case REMOVE: os << "REMOVE"; return os; 00257 case ADD_CHANGE: os << "ADD_CHANGE"; return os; 00258 default: assert(false); return os; 00259 } 00260 } 00261 00262 00263 /** This type defines the types of callback events possible. */ 00264 enum Signal 00265 { 00266 /** Adding a new entity. */ 00267 SIG_ADD = 0, 00268 /** Deleting an entity. */ 00269 SIG_REMOVE = 1 00270 }; 00271 00272 00273 /** Writes a signal description to an output stream. */ 00274 inline ostream & operator << (ostream & os, const Signal & d) 00275 { 00276 switch (d) 00277 { 00278 case SIG_ADD: os << "ADD"; return os; 00279 case SIG_REMOVE: os << "REMOVE"; return os; 00280 default: assert(false); return os; 00281 } 00282 } 00283 00284 00285 /** This is the datatype used for hashing an XML-element to a numeric value. */ 00286 typedef unsigned int hashtype; 00287 00288 /** This stream is the general output for all logging and debugging messages. */ 00289 extern DECLARE_EXPORT ostream logger; 00290 00291 /** Auxilary structure for easy indenting in the log stream. */ 00292 struct indent 00293 { 00294 short level; 00295 indent(short l) : level(l) {} 00296 indent operator() (short l) {return indent(l);} 00297 }; 00298 00299 /** Print a number of spaces to the output stream. */ 00300 inline ostream& operator <<(ostream &os, const indent& i) 00301 { 00302 for (short c = i.level; c>0; --c) os << ' '; 00303 return os; 00304 } 00305 00306 00307 00308 // 00309 // CUSTOM EXCEPTION CLASSES 00310 // 00311 00312 00313 /** @brief An exception of this type is thrown when data errors are found. 00314 * 00315 * The normal handling of this error is to catch the exception and 00316 * continue execution of the rest of the program.<br> 00317 * When a DataException is thrown the object is expected to remain in 00318 * valid and consistent state. 00319 */ 00320 class DataException : public logic_error 00321 { 00322 public: 00323 DataException(const char * c) : logic_error(c) {} 00324 DataException(const string s) : logic_error(s) {} 00325 }; 00326 00327 00328 /** @brief An exception of this type is thrown when the library gets in an 00329 * inconsistent state from which the normal course of action can't continue. 00330 * 00331 * The normal handling of this error is to exit the program, and report the 00332 * problem. This exception indicates a bug in the program code. 00333 */ 00334 class LogicException: public logic_error 00335 { 00336 public: 00337 LogicException(const char * c) : logic_error(c) {} 00338 LogicException(const string s) : logic_error(s) {} 00339 }; 00340 00341 00342 /** @brief An exception of this type is thrown when the library runs into 00343 * problems that are specific at runtime. <br> 00344 * These could either be memory problems, threading problems, file system 00345 * problems, etc... 00346 * 00347 * Errors of this type can be caught by the client applications and the 00348 * application can continue in most cases.<br> 00349 * This exception shouldn't be used for issueing warnings. Warnings should 00350 * simply be logged in the logfile and actions continue in some default way. 00351 */ 00352 class RuntimeException: public runtime_error 00353 { 00354 public: 00355 RuntimeException(const char * c) : runtime_error(c) {} 00356 RuntimeException(const string s) : runtime_error(s) {} 00357 }; 00358 00359 00360 /** @brief Python exception class matching with frepple::LogicException. */ 00361 extern DECLARE_EXPORT PyObject* PythonLogicException; 00362 00363 /** @brief Python exception class matching with frepple::DataException. */ 00364 extern DECLARE_EXPORT PyObject* PythonDataException; 00365 00366 /** @brief Python exception class matching with frepple::RuntimeException. */ 00367 extern DECLARE_EXPORT PyObject* PythonRuntimeException; 00368 00369 00370 // 00371 // UTILITY CLASS "NON-COPYABLE" 00372 // 00373 00374 /** @brief Class NonCopyable is a base class.<br>Derive your own class from 00375 * it when you want to prohibit copy construction and copy assignment. 00376 * 00377 * Some objects, particularly those which hold complex resources like files 00378 * or network connections, have no sensible copy semantics. Sometimes there 00379 * are possible copy semantics, but these would be of very limited usefulness 00380 * and be very difficult to implement correctly. Sometimes you're implementing 00381 * a class that doesn't need to be copied just yet and you don't want to 00382 * take the time to write the appropriate functions. Deriving from 00383 * noncopyable will prevent the otherwise implicitly-generated functions 00384 * (which don't have the proper semantics) from becoming a trap for other 00385 * programmers.<br> 00386 * The traditional way to deal with these is to declare a private copy 00387 * constructor and copy assignment, and then document why this is done. But 00388 * deriving from NonCopyable is simpler and clearer, and doesn't require 00389 * additional documentation. 00390 */ 00391 class NonCopyable 00392 { 00393 protected: 00394 NonCopyable() {} 00395 ~NonCopyable() {} 00396 00397 private: 00398 /** This copy constructor isn't implemented.<br> 00399 * It's here just so we can declare them as private so that this, and 00400 * any derived class, do not have copy constructors. 00401 */ 00402 NonCopyable(const NonCopyable&); 00403 00404 /** This assignment operator isn't implemented.<br> 00405 * It's here just so we can declare them as private so that this, and 00406 * any derived class, do not have copy constructors. 00407 */ 00408 NonCopyable& operator=(const NonCopyable&); 00409 }; 00410 00411 00412 /** @brief This class is used to maintain the Python interpreter. 00413 * 00414 * A single interpreter is used throughout the lifetime of the 00415 * application.<br> 00416 * The implementation is implemented in a thread-safe way (within the 00417 * limitations of the Python threading model, of course). 00418 * 00419 * During the initialization the code checks for a file 'init.py' in its 00420 * search path and, if it does exist, the statements in the file will be 00421 * executed. In this way a library of globally available functions 00422 * can easily be initialized. 00423 * 00424 * The stderr and stdout streams of Python are redirected by default to 00425 * the frePPLe log stream. 00426 * 00427 * The following frePPLe functions are available from within Python.<br> 00428 * All of these are in the module called frePPLe. 00429 * - The following <b>classes</b> and their attributes are accessible for 00430 * reading and writing.<br> 00431 * Each object has a toXML() method that returns its XML representation 00432 * as a string, or writes it to a file is a file is passed as argument. 00433 * - buffer 00434 * - buffer_default 00435 * - buffer_infinite 00436 * - buffer_procure 00437 * - calendar 00438 * - calendarBucket 00439 * - calendar_boolean 00440 * - calendar_double 00441 * - calendar_void 00442 * - customer 00443 * - customer_default 00444 * - demand 00445 * - demand_default 00446 * - flow 00447 * - flowplan 00448 * - item 00449 * - item_default 00450 * - load 00451 * - loadplan 00452 * - location 00453 * - location_default 00454 * - operation 00455 * - operation_alternate 00456 * - addAlternate(operation=x, priority=y, effective_start=z1, effective_end=z2) 00457 * - operation_fixed_time 00458 * - operation_routing 00459 * - addStep(tuple of operations) 00460 * - operation_time_per 00461 * - operationplan 00462 * - parameters 00463 * - problem (read-only) 00464 * - resource 00465 * - resource_default 00466 * - resource_infinite 00467 * - setup_matrix 00468 * - setup_matrix_default 00469 * - solver 00470 * - solve() 00471 * - solver_mrp 00472 * - The following functions or attributes return <b>iterators</b> over the 00473 * frePPLe objects:<br> 00474 * - buffers() 00475 * - buffer.flows 00476 * - buffer.flowplans 00477 * - calendar.buckets 00478 * - calendars() 00479 * - customers() 00480 * - demands() 00481 * - demand.operationplans 00482 * - demand.pegging 00483 * - operation.flows 00484 * - operation.loads 00485 * - items() 00486 * - locations() 00487 * - operations() 00488 * - operation.operationplans 00489 * - problems() 00490 * - resources() 00491 * - resource.loads 00492 * - resource.loadplans 00493 * - setup_matrices() 00494 * - solvers() 00495 * - <b>printsize()</b>:<br> 00496 * Prints information about the memory consumption. 00497 * - <b>loadmodule(string [,parameter=value, ...])</b>:<br> 00498 * Dynamically load a module in memory. 00499 * - <b>readXMLdata(string [,bool] [,bool])</b>:<br> 00500 * Processes an XML string passed as argument. 00501 * - <b>log(string)</b>:<br> 00502 * Prints a string to the frePPLe log file.<br> 00503 * This is used for redirecting the stdout and stderr of Python. 00504 * - <b>readXMLfile(string [,bool] [,bool])</b>:<br> 00505 * Read an XML-file. 00506 * - <b>saveXMLfile(string)</b>:<br> 00507 * Save the model to an XML-file. 00508 * - <b>saveplan(string)</b>:<br> 00509 * Save the main plan information to a file. 00510 * - <b>erase(boolean)</b>:<br> 00511 * Erase the model (arg true) or only the plan (arg false, default). 00512 * - <b>version</b>:<br> 00513 * A string variable with the version number. 00514 * 00515 * The technical implementation is inspired by and inherited from the following 00516 * article: "Embedding Python in Multi-Threaded C/C++ Applications", see 00517 * http://www.linuxjournal.com/article/3641 00518 */ 00519 class PythonInterpreter 00520 { 00521 public: 00522 /** Initializes the interpreter. */ 00523 static DECLARE_EXPORT void initialize(int argc, char** argv); 00524 00525 /** Finalizes the interpreter. */ 00526 static DECLARE_EXPORT void finalize(); 00527 00528 /** Execute some python code. */ 00529 static DECLARE_EXPORT void execute(const char*); 00530 00531 /** Execute a file with Python code. */ 00532 static DECLARE_EXPORT void executeFile(string); 00533 00534 /** Register a new method to Python.<br> 00535 * Arguments: 00536 * - The name of the built-in function/method 00537 * - The function that implements it. 00538 * - Combination of METH_* flags, which mostly describe the args 00539 * expected by the C func. 00540 * - The __doc__ attribute, or NULL. 00541 */ 00542 static DECLARE_EXPORT void registerGlobalMethod( 00543 const char*, PyCFunction, int, const char*, bool = true 00544 ); 00545 00546 /** Register a new method to Python. */ 00547 static DECLARE_EXPORT void registerGlobalMethod 00548 (const char*, PyCFunctionWithKeywords, int, const char*, bool = true); 00549 00550 /** Return a pointer to the main extension module. */ 00551 static PyObject* getModule() {return module;} 00552 00553 /** Return the preferred encoding of the Python interpreter. */ 00554 static const char* getPythonEncoding() {return encoding.c_str();} 00555 00556 /** Create a new Python thread state.<br> 00557 * Each OS-level thread needs to initialize a Python thread state as well. 00558 * When a new thread is created in the OS, this method should be called 00559 * to create a Python thread state as well.<br> 00560 * See the Python PyGILState_Ensure API. 00561 */ 00562 static DECLARE_EXPORT void addThread(); 00563 00564 /** Delete a Python thread state.<br> 00565 * Each OS-level thread has a Python thread state. 00566 * When an OS thread is deleted, this method should be called 00567 * to delete the Python thread state as well.<br> 00568 * See the Python PyGILState_Release API. 00569 */ 00570 static DECLARE_EXPORT void deleteThread(); 00571 00572 private: 00573 /** A pointer to the frePPLe extension module. */ 00574 static DECLARE_EXPORT PyObject *module; 00575 00576 /** Python API: Used for redirecting the Python output to the same file 00577 * as the application. 00578 */ 00579 static DECLARE_EXPORT PyObject *python_log(PyObject*, PyObject*); 00580 00581 /** Python unicode strings are encoded to this locale when bringing them into 00582 * frePPLe.<br> 00583 */ 00584 static DECLARE_EXPORT string encoding; 00585 00586 /** Main thread info. */ 00587 static DECLARE_EXPORT PyThreadState* mainThreadState; 00588 }; 00589 00590 00591 /** A utility function to do wildcard matching in strings.<br> 00592 * The function recognizes two wildcard characaters: 00593 * - ?: matches any single character 00594 * - *: matches any sequence of characters 00595 * 00596 * The code is written by Jack Handy (jakkhandy@hotmail.com) and published 00597 * on http://www.codeproject.com/KB/string/wildcmp.aspx. No specific license 00598 * constraints apply on using the code. 00599 */ 00600 DECLARE_EXPORT bool matchWildcard(const char*, const char*); 00601 00602 00603 // 00604 // METADATA AND OBJECT FACTORY 00605 // 00606 00607 /** @brief This class defines a keyword for the frePPLe data model. 00608 * 00609 * The keywords are used to define the attribute names for the objects.<br> 00610 * They are used as: 00611 * - Element and attribute names in XML documents 00612 * - Attribute names in the Python extension. 00613 * 00614 * Special for this class is the requirement to have a "perfect" hash 00615 * function, i.e. a function that returns a distinct number for each 00616 * defined tag. The class prints a warning message when the hash 00617 * function doesn't satisfy this criterion. 00618 */ 00619 class Keyword : public NonCopyable 00620 { 00621 private: 00622 /** Stores the hash value of this tag. */ 00623 hashtype dw; 00624 00625 /** Store different preprocessed variations of the name of the tag. 00626 * These are all stored in memory for improved performance. */ 00627 string strName, strStartElement, strEndElement, strElement, strAttribute; 00628 00629 /** Name of the string transcoded to its Xerces-internal representation. */ 00630 XMLCh* xmlname; 00631 00632 /** A function to verify the uniquess of our hashes. */ 00633 void check(); 00634 00635 public: 00636 /** Container for maintaining a list of all tags. */ 00637 typedef map<hashtype,Keyword*> tagtable; 00638 00639 /** This is the constructor.<br> 00640 * The tag doesn't belong to an XML namespace. */ 00641 DECLARE_EXPORT Keyword(const string&); 00642 00643 /** This is the constructor. The tag belongs to the XML namespace passed 00644 * as second argument.<br> 00645 * Note that we still require the first argument to be unique, since it 00646 * is used as a keyword for the Python extensions. 00647 */ 00648 DECLARE_EXPORT Keyword(const string&, const string&); 00649 00650 /** Destructor. */ 00651 DECLARE_EXPORT ~Keyword(); 00652 00653 /** Returns the hash value of the tag. */ 00654 hashtype getHash() const {return dw;} 00655 00656 /** Returns the name of the tag. */ 00657 const string& getName() const {return strName;} 00658 00659 /** Returns a pointer to an array of XML characters. This format is used 00660 * by Xerces for the internal representation of character strings. */ 00661 const XMLCh* getXMLCharacters() const {return xmlname;} 00662 00663 /** Returns a string to start an XML element with this tag: <TAG */ 00664 const string& stringStartElement() const {return strStartElement;} 00665 00666 /** Returns a string to end an XML element with this tag: </TAG> */ 00667 const string& stringEndElement() const {return strEndElement;} 00668 00669 /** Returns a string to start an XML element with this tag: <TAG> */ 00670 const string& stringElement() const {return strElement;} 00671 00672 /** Returns a string to start an XML attribute with this tag: TAG=" */ 00673 const string& stringAttribute() const {return strAttribute;} 00674 00675 /** This is the hash function. See the note on the perfectness of 00676 * this function at the start. This function should be as simple 00677 * as possible while still garantueeing the perfectness.<br> 00678 * The hash function is based on the Xerces-C implementation, 00679 * with the difference that the hash calculated by our function is 00680 * portable between platforms.<br> 00681 * The hash modulus is 954991 (which is the biggest prime number 00682 * lower than 1000000). 00683 */ 00684 static DECLARE_EXPORT hashtype hash(const char*); 00685 00686 /** This is the hash function. 00687 * @see hash(const char*) 00688 */ 00689 static hashtype hash(const string& c) {return hash(c.c_str());} 00690 00691 /** This is the hash function taken an XML character string as input.<br> 00692 * The function is expected to return exactly the same result as when a 00693 * character pointer is passed as argument. 00694 * @see hash(const char*) 00695 */ 00696 static DECLARE_EXPORT hashtype hash(const XMLCh*); 00697 00698 /** Finds a tag when passed a certain string. If no tag exists yet, it 00699 * will be created. */ 00700 static DECLARE_EXPORT const Keyword& find(const char*); 00701 00702 /** Return a reference to a table with all defined tags. */ 00703 static DECLARE_EXPORT tagtable& getTags(); 00704 00705 /** Prints a list of all tags that have been defined. This can be useful 00706 * for debugging and also for creating a good hashing function.<br> 00707 * GNU gperf is a program that can generate a perfect hash function for 00708 * a given set of symbols. 00709 */ 00710 static DECLARE_EXPORT void printTags(); 00711 }; 00712 00713 00714 /** @brief This abstract class is the base class used for callbacks. 00715 * @see MetaClass::callback 00716 * @see FunctorStatic 00717 * @see FunctorInstance 00718 */ 00719 class Functor : public NonCopyable 00720 { 00721 public: 00722 /** This is the callback method.<br> 00723 * The return value should be true in case the action is allowed to 00724 * happen. In case a subscriber disapproves the action false is 00725 * returned.<br> 00726 * It is important that the callback methods are implemented in a 00727 * thread-safe and re-entrant way!!! 00728 */ 00729 virtual bool callback(Object* v, const Signal a) const = 0; 00730 00731 /** Destructor. */ 00732 virtual ~Functor() {} 00733 }; 00734 00735 00736 // The following handler functions redirect the call from Python onto a 00737 // matching virtual function in a PythonExtensionBase subclass. 00738 extern "C" 00739 { 00740 /** Handler function called from Python. Internal use only. */ 00741 DECLARE_EXPORT PyObject* getattro_handler (PyObject*, PyObject*); 00742 /** Handler function called from Python. Internal use only. */ 00743 DECLARE_EXPORT int setattro_handler (PyObject*, PyObject*, PyObject*); 00744 /** Handler function called from Python. Internal use only. */ 00745 DECLARE_EXPORT int compare_handler (PyObject*, PyObject*); 00746 /** Handler function called from Python. Internal use only. */ 00747 DECLARE_EXPORT PyObject* iternext_handler (PyObject*); 00748 /** Handler function called from Python. Internal use only. */ 00749 DECLARE_EXPORT PyObject* call_handler(PyObject*, PyObject*, PyObject*); 00750 /** Handler function called from Python. Internal use only. */ 00751 DECLARE_EXPORT PyObject* str_handler(PyObject*); 00752 } 00753 00754 00755 /** @brief This class is a thin wrapper around the type information in Python. 00756 * 00757 * This class defines a number of convenience functions to interact with the 00758 * PyTypeObject struct of the Python C API. 00759 */ 00760 class PythonType : public NonCopyable 00761 { 00762 private: 00763 /** This static variable is a template for cloning type definitions.<br> 00764 * It is copied for each type object we create. 00765 */ 00766 static const PyTypeObject PyTypeObjectTemplate; 00767 00768 /** Incremental size of the method table.<br> 00769 * We allocate memory for the method definitions per block, not 00770 * one-by-one. 00771 */ 00772 static const unsigned short methodArraySize = 5; 00773 00774 /** The Python type object which this class is wrapping. */ 00775 PyTypeObject* table; 00776 00777 public: 00778 /** A static function that evaluates an exception and sets the Python 00779 * error string properly.<br> 00780 * This function should only be called from within a catch-block, since 00781 * internally it rethrows the exception! 00782 */ 00783 static DECLARE_EXPORT void evalException(); 00784 00785 /** Constructor, sets the tp_base_size member. */ 00786 DECLARE_EXPORT PythonType(size_t, const type_info*); 00787 00788 /** Return a pointer to the actual Python PyTypeObject. */ 00789 PyTypeObject* type_object() const {return table;} 00790 00791 /** Add a new method. */ 00792 DECLARE_EXPORT void addMethod(const char*, PyCFunction, int, const char*); 00793 00794 /** Add a new method. */ 00795 DECLARE_EXPORT void addMethod(const char*, PyCFunctionWithKeywords, int, const char*); 00796 00797 /** Updates tp_name. */ 00798 void setName (const string n) 00799 { 00800 string *name = new string("frepple." + n); 00801 table->tp_name = const_cast<char*>(name->c_str()); 00802 } 00803 00804 /** Updates tp_doc. */ 00805 void setDoc (const string n) 00806 { 00807 string *doc = new string(n); 00808 table->tp_doc = const_cast<char*>(doc->c_str()); 00809 } 00810 00811 /** Updates tp_base. */ 00812 void setBase(PyTypeObject* b) 00813 { 00814 table->tp_base = b; 00815 } 00816 00817 /** Updates the deallocator. */ 00818 void supportdealloc(void (*f)(PyObject*)) 00819 { 00820 table->tp_dealloc = f; 00821 } 00822 00823 /** Updates tp_getattro.<br> 00824 * The extension class will need to define a member function with this 00825 * prototype:<br> 00826 * PythonObject getattro(const XMLElement& name) 00827 */ 00828 void supportgetattro() 00829 {table->tp_getattro = getattro_handler;} 00830 00831 /** Updates tp_setattro.<br> 00832 * The extension class will need to define a member function with this 00833 * prototype:<br> 00834 * int setattro(const Attribute& attr, const PythonObject& field) 00835 */ 00836 void supportsetattro() 00837 {table->tp_setattro = setattro_handler;} 00838 00839 /** Updates tp_compare.<br> 00840 * The extension class will need to define a member function with this 00841 * prototype:<br> 00842 * int compare(const PyObject* other) const 00843 */ 00844 void supportcompare() 00845 {table->tp_compare = compare_handler;} 00846 00847 /** Updates tp_iter and tp_iternext.<br> 00848 * The extension class will need to define a member function with this 00849 * prototype:<br> 00850 * PyObject* iternext() 00851 */ 00852 void supportiter() 00853 { 00854 table->tp_iter = PyObject_SelfIter; 00855 table->tp_iternext = iternext_handler; 00856 } 00857 00858 /** Updates tp_call.<br> 00859 * The extension class will need to define a member function with this 00860 * prototype:<br> 00861 * PyObject* call(const PythonObject& args, const PythonObject& kwds) 00862 */ 00863 void supportcall() 00864 {table->tp_call = call_handler;} 00865 00866 /** Updates tp_str.<br> 00867 * The extension class will need to define a member function with this 00868 * prototype:<br> 00869 * PyObject* str() 00870 */ 00871 void supportstr() 00872 {table->tp_str = str_handler;} 00873 00874 /** Type definition for create functions. */ 00875 typedef PyObject* (*createfunc)(PyTypeObject*, PyObject*, PyObject*); 00876 00877 /** Updates tp_new with the function passed as argument. */ 00878 void supportcreate(createfunc c) {table->tp_new = c;} 00879 00880 /** This method needs to be called after the type information has all 00881 * been updated. It adds the type to the frepple module. */ 00882 DECLARE_EXPORT int typeReady(); 00883 00884 /** Comparison operator. */ 00885 bool operator == (const PythonType& i) const 00886 { 00887 return *cppClass == *(i.cppClass); 00888 } 00889 00890 /** Comparison operator. */ 00891 bool operator == (const type_info& i) const 00892 { 00893 return *cppClass == i; 00894 } 00895 00896 /** Type info of the registering class. */ 00897 const type_info* cppClass; 00898 }; 00899 00900 00901 class MetaCategory; 00902 /** @brief This class stores metadata about the classes in the library. 00903 * The stored information goes well beyond the standard 'type_info'. 00904 * 00905 * A MetaClass instance represents metadata for a specific instance type. 00906 * A MetaCategory instance represents metadata for a category of object. 00907 * For instance, 'Resource' is a category while 'ResourceDefault' and 00908 * 'ResourceInfinite' are specific classes.<br> 00909 * The metadata class also maintains subscriptions to certain events. 00910 * Registered classes and objects will receive callbacks when objects are 00911 * being created, changed or deleted.<br> 00912 * The proper usage is to include the following code snippet in every 00913 * class:<br> 00914 * @code 00915 * In the header file: 00916 * class X : public Object 00917 * { 00918 * public: 00919 * virtual const MetaClass& getType() {return *metadata;} 00920 * static const MetaClass *metadata; 00921 * } 00922 * In the implementation file: 00923 * const MetaClass *X::metadata; 00924 * @endcode 00925 * Creating a MetaClass object isn't sufficient. It needs to be registered, 00926 * typically in an initialization method: 00927 * @code 00928 * void initialize() 00929 * { 00930 * ... 00931 * Y::metadata = new MetaCategory("Y","Ys", reader_method, writer_method); 00932 * X::metadata = new MetaClass("Y","X", factory_method); 00933 * ... 00934 * } 00935 * @endcode 00936 * @see MetaCategory 00937 */ 00938 class MetaClass : public NonCopyable 00939 { 00940 friend class MetaCategory; 00941 template <class T, class U> friend class FunctorStatic; 00942 template <class T, class U> friend class FunctorInstance; 00943 00944 public: 00945 /** Type definition for a factory method calling the default 00946 * constructor.. */ 00947 typedef Object* (*creatorDefault)(); 00948 00949 /** Type definition for a factory method calling the constructor that 00950 * takes a string as argument. */ 00951 typedef Object* (*creatorString)(const string&); 00952 00953 /** A string specifying the object type, i.e. the subclass within the 00954 * category. */ 00955 string type; 00956 00957 /** A reference to an Keyword of the base string. */ 00958 const Keyword* typetag; 00959 00960 /** The category of this class. */ 00961 const MetaCategory* category; 00962 00963 /** A pointer to the Python type. */ 00964 PyTypeObject* pythonClass; 00965 00966 /** A factory method for the registered class. */ 00967 union 00968 { 00969 creatorDefault factoryMethodDefault; 00970 creatorString factoryMethodString; 00971 }; 00972 00973 /** Destructor. */ 00974 virtual ~MetaClass() {} 00975 00976 /** Initialize the data structure and register the class. */ 00977 DECLARE_EXPORT void registerClass(const string&, const string&, 00978 bool = false, creatorDefault = NULL); 00979 00980 /** This constructor registers the metadata of a class. */ 00981 MetaClass (const string& cat, const string& cls, bool def = false) 00982 : pythonClass(NULL) 00983 { 00984 registerClass(cat,cls,def); 00985 } 00986 00987 /** This constructor registers the metadata of a class, with a factory 00988 * method that uses the default constructor of the class. */ 00989 MetaClass (const string& cat, const string& cls, creatorDefault f, 00990 bool def = false) : pythonClass(NULL) 00991 { 00992 registerClass(cat,cls,def); 00993 factoryMethodDefault = f; 00994 } 00995 00996 /** This constructor registers the metadata of a class, with a factory 00997 * method that uses a constructor with a string argument. */ 00998 MetaClass (const string& cat, const string& cls, creatorString f, 00999 bool def = false) : pythonClass(NULL) 01000 { 01001 registerClass(cat,cls,def); 01002 factoryMethodString = f; 01003 } 01004 01005 /** This function will analyze the string being passed, and return the 01006 * appropriate action. 01007 * The string is expected to be one of the following: 01008 * - 'A' for action ADD 01009 * - 'C' for action CHANGE 01010 * - 'AC' for action ADD_CHANGE 01011 * - 'R' for action REMOVE 01012 * - Any other value will result in a data exception 01013 */ 01014 static DECLARE_EXPORT Action decodeAction(const char*); 01015 01016 /** This method picks up the attribute named "ACTION" from the list and 01017 * calls the method decodeAction(const XML_Char*) to analyze it. 01018 * @see decodeAction(const XML_Char*) 01019 */ 01020 static DECLARE_EXPORT Action decodeAction(const AttributeList&); 01021 01022 /** Sort two metaclass objects. This is used to sort entities on their 01023 * type information in a stable and platform independent way. 01024 * @see operator != 01025 * @see operator == 01026 */ 01027 bool operator < (const MetaClass& b) const 01028 { 01029 return typetag->getHash() < b.typetag->getHash(); 01030 } 01031 01032 /** Compare two metaclass objects. We are not always sure that only a 01033 * single instance of a metadata object exists in the system, and a 01034 * pointer comparison is therefore not appropriate. 01035 * @see operator != 01036 * @see operator < 01037 */ 01038 bool operator == (const MetaClass& b) const 01039 { 01040 return typetag->getHash() == b.typetag->getHash(); 01041 } 01042 01043 /** Compare two metaclass objects. We are not always sure that only a 01044 * single instance of a metadata object exists in the system, and a 01045 * pointer comparison is therefore not appropriate. 01046 * @see operator == 01047 * @see operator < 01048 */ 01049 bool operator != (const MetaClass& b) const 01050 { 01051 return typetag->getHash() != b.typetag->getHash(); 01052 } 01053 01054 /** This method should be called whenever objects of this class are being 01055 * created, updated or deleted. It will run the callback method of all 01056 * subscribers.<br> 01057 * If the function returns true, all callback methods approved of the 01058 * event. If false is returned, one of the callbacks disapproved it and 01059 * the event action should be allowed to execute. 01060 */ 01061 DECLARE_EXPORT bool raiseEvent(Object* v, Signal a) const; 01062 01063 /** Connect a new subscriber to the class. */ 01064 void connect(Functor *c, Signal a) const 01065 {const_cast<MetaClass*>(this)->subscribers[a].push_front(c);} 01066 01067 /** Disconnect a subscriber from the class. */ 01068 void disconnect(Functor *c, Signal a) const 01069 {const_cast<MetaClass*>(this)->subscribers[a].remove(c);} 01070 01071 /** Print all registered factory methods to the standard output for 01072 * debugging purposes. */ 01073 static DECLARE_EXPORT void printClasses(); 01074 01075 /** Find a particular class by its name. If it can't be located the return 01076 * value is NULL. */ 01077 static DECLARE_EXPORT const MetaClass* findClass(const char*); 01078 01079 protected: 01080 /** Default constructor. */ 01081 MetaClass() : type("unspecified"), typetag(&Keyword::find("unspecified")), 01082 category(NULL), pythonClass(NULL), factoryMethodDefault(NULL) {} 01083 01084 private: 01085 /** This is a list of objects that will receive a callback when the call 01086 * method is being used.<br> 01087 * There is limited error checking in maintaining this list, and it is the 01088 * user's responsability of calling the connect() and disconnect() methods 01089 * correctly.<br> 01090 * This design garantuees maximum performance, but assumes a properly 01091 * educated user. 01092 */ 01093 list<Functor*> subscribers[4]; 01094 }; 01095 01096 01097 class XMLOutput; 01098 01099 /** @brief This class stores metadata on a data field of a class. 01100 * 01101 * A field 01102 */ 01103 //class MetaField : public NonCopyable 01104 //{ 01105 // private: 01106 // Keyword& name; 01107 // 01108 // public: 01109 // typedef double (*getDouble)() const; 01110 // typedef void (*setDouble)(double); 01111 // typedef int (*getInt)() const; 01112 // typedef void (*setInt)(int); 01113 // typedef long (*getLong)() const; 01114 // typedef void (*setLong)(long); 01115 // typedef unsigned long (*getUnsignedLong)() const; 01116 // typedef void (*setUnsignedLong)(unsigned long); 01117 // typedef bool (*getBool)() const; 01118 // typedef void (*setBool)(int); 01119 // typedef bool (*getString)() const; 01120 // typedef void (*setString)(string); 01121 // typedef Date (*getDate)() const; 01122 // typedef void (*setDate)(Date); 01123 // typedef TimePeriod (*getTimePeriod)() const; 01124 // typedef void (*setTimePeriod)(TimePeriod); 01125 // /* Other types: list of things... */ 01126 // 01127 // /** Constructor. */ 01128 // MetaField(Keyword&, getDouble, setDouble); 01129 // MetaField(Keyword&, getInt, setInt); 01130 // MetaField(Keyword&, getBool, setBool); 01131 // MetaField(Keyword&, getString, setString ); 01132 // template <class T> MetaField(Keyword&, T*(*getFunction)() const, void (*setFunction)(T*)); 01133 // 01134 // bool get(Object*); 01135 // int get(Object*); 01136 // double get(Object*); 01137 // string get(Object*); 01138 // 01139 // void set(Object*, bool); 01140 // void set(Object*, int); 01141 // void set(Object*, double); 01142 // void set(Object*, string); 01143 // 01144 // /* for class MetaClass: */ 01145 // void write(writer, object*); 01146 // void read(reader, Object*); 01147 //}; 01148 01149 01150 /** @brief A MetaCategory instance represents metadata for a category of 01151 * object. 01152 * 01153 * A MetaClass instance represents metadata for a specific instance type. 01154 * For instance, 'Resource' is a category while 'ResourceDefault' and 01155 * 'ResourceInfinite' are specific classes.<br> 01156 * A category has the following specific pieces of data: 01157 * - A reader function for creating objects.<br> 01158 * The reader function creates objects for all classes registered with it. 01159 * - A writer function for persisting objects.<br> 01160 * The writer function will typically iterate over all objects of the 01161 * category and call the writeElement method on them. 01162 * - A group tag used for the grouping objects of the category in the XML 01163 * output stream. 01164 * @see MetaClass 01165 */ 01166 class MetaCategory : public MetaClass 01167 { 01168 friend class MetaClass; 01169 template<class T> friend class HasName; 01170 public: 01171 /** The name used to name a collection of objects of this category. */ 01172 string group; 01173 01174 /** A XML tag grouping objects of the category. */ 01175 const Keyword* grouptag; 01176 01177 /** Type definition for the read control function. */ 01178 typedef Object* (*readController)(const MetaClass*, const AttributeList&); 01179 01180 /** Type definition for the write control function. */ 01181 typedef void (*writeController)(const MetaCategory*, XMLOutput *o); 01182 01183 /** This template method is available as a object creation factory for 01184 * classes without key fields and which rely on a default constructor. 01185 */ 01186 static Object* ControllerDefault (const MetaClass*, const AttributeList&); 01187 01188 /** Destructor. */ 01189 virtual ~MetaCategory() {} 01190 01191 /** Constructor. */ 01192 DECLARE_EXPORT MetaCategory (const string& t, const string& g, 01193 readController = NULL, writeController = NULL); 01194 01195 /** Type definition for the map of all registered classes. */ 01196 typedef map < hashtype, const MetaClass*, less<hashtype> > ClassMap; 01197 01198 /** Type definition for the map of all categories. */ 01199 typedef map < hashtype, const MetaCategory*, less<hashtype> > CategoryMap; 01200 01201 /** Looks up a category name in the registry. If the catgory can't be 01202 * located the return value is NULL. */ 01203 static DECLARE_EXPORT const MetaCategory* findCategoryByTag(const char*); 01204 01205 /** Looks up a category name in the registry. If the catgory can't be 01206 * located the return value is NULL. */ 01207 static DECLARE_EXPORT const MetaCategory* findCategoryByTag(const hashtype); 01208 01209 /** Looks up a category name in the registry. If the catgory can't be 01210 * located the return value is NULL. */ 01211 static DECLARE_EXPORT const MetaCategory* findCategoryByGroupTag(const char*); 01212 01213 /** Looks up a category name in the registry. If the category can't be 01214 * located the return value is NULL. */ 01215 static DECLARE_EXPORT const MetaCategory* findCategoryByGroupTag(const hashtype); 01216 01217 /** Find a class in this category with a specified name.<br> 01218 * If the catrgory can't be found the return value is NULL. 01219 */ 01220 DECLARE_EXPORT const MetaClass* findClass(const char*) const; 01221 01222 /** Find a class in this category with a specified name.<br> 01223 * If the catrgory can't be found the return value is NULL. 01224 */ 01225 DECLARE_EXPORT const MetaClass* findClass(const hashtype) const; 01226 01227 /** This method takes care of the persistence of all categories. It loops 01228 * through all registered categories (in the order of their registration) 01229 * and calls the persistance handler. 01230 */ 01231 static DECLARE_EXPORT void persist(XMLOutput *); 01232 01233 /** A control function for reading objects of a category. 01234 * The controller function manages the creation and destruction of 01235 * objects in this category. 01236 */ 01237 readController readFunction; 01238 01239 private: 01240 /** A map of all classes registered for this category. */ 01241 ClassMap classes; 01242 01243 /** Compute the hash for "default" once and store it in this variable for 01244 * efficiency. */ 01245 static DECLARE_EXPORT const hashtype defaultHash; 01246 01247 /** This is the root for a linked list of all categories. 01248 * Categories are chained to the list in the order of their registration. 01249 */ 01250 static DECLARE_EXPORT const MetaCategory* firstCategory; 01251 01252 /** A pointer to the next category in the singly linked list. */ 01253 const MetaCategory* nextCategory; 01254 01255 /** A control function for writing the category. 01256 * The controller function will loop over the objects in the category and 01257 * call write them one by one. 01258 */ 01259 writeController writeFunction; 01260 01261 /** A map of all categories by their name. */ 01262 static DECLARE_EXPORT CategoryMap categoriesByTag; 01263 01264 /** A map of all categories by their group name. */ 01265 static DECLARE_EXPORT CategoryMap categoriesByGroupTag; 01266 }; 01267 01268 01269 /** @brief This class represents a static subscription to a signal. 01270 * 01271 * When the signal callback is triggered the static method callback() on the 01272 * parameter class will be called. 01273 */ 01274 template <class T, class U> class FunctorStatic : public Functor 01275 { 01276 friend class MetaClass; 01277 public: 01278 /** Add a signal subscriber. */ 01279 static void connect(const Signal a) 01280 {T::metadata->connect(new FunctorStatic<T,U>(), a);} 01281 01282 /** Remove a signal subscriber. */ 01283 static void disconnect(const Signal a) 01284 { 01285 MetaClass &t = 01286 const_cast<MetaClass&>(static_cast<const MetaClass&>(*T::metadata)); 01287 // Loop through all subscriptions 01288 for (list<Functor*>::iterator i = t.subscribers[a].begin(); 01289 i != t.subscribers[a].end(); ++i) 01290 { 01291 // Try casting the functor to the right type 01292 FunctorStatic<T,U> *f = dynamic_cast< FunctorStatic<T,U>* >(*i); 01293 if (f) 01294 { 01295 // Casting was successfull. Delete the functor. 01296 delete *i; 01297 t.subscribers[a].erase(i); 01298 return; 01299 } 01300 } 01301 // Not found in the list of subscriptions 01302 throw LogicException("Subscription doesn't exist"); 01303 } 01304 01305 private: 01306 /** This is the callback method. The functor will call the static callback 01307 * method of the subscribing class. 01308 */ 01309 virtual bool callback(Object* v, const Signal a) const 01310 {return U::callback(static_cast<T*>(v),a);} 01311 }; 01312 01313 01314 /** @brief This class represents an object subscribing to a signal. 01315 * 01316 * When the signal callback is triggered the method callback() on the 01317 * instance object will be called. 01318 */ 01319 template <class T, class U> class FunctorInstance : public Functor 01320 { 01321 public: 01322 /** Connect a new subscriber to a signal.<br> 01323 * It is the users' responsibility to call the disconnect method 01324 * when the subscriber is being deleted. Otherwise the application 01325 * will crash. 01326 */ 01327 static void connect(U* u, const Signal a) 01328 {if (u) T::metadata.connect(new FunctorInstance(u), a);} 01329 01330 /** Disconnect from a signal. */ 01331 static void disconnect(U *u, const Signal a) 01332 { 01333 MetaClass &t = 01334 const_cast<MetaClass&>(static_cast<const MetaClass&>(T::metadata)); 01335 // Loop through all subscriptions 01336 for (list<Functor*>::iterator i = t.subscribers[a].begin(); 01337 i != t.subscribers[a].end(); ++i) 01338 { 01339 // Try casting the functor to the right type 01340 FunctorInstance<T,U> *f = dynamic_cast< FunctorInstance<T,U>* >(*i); 01341 if (f && f->instance == u) 01342 { 01343 // Casting was successfull. Delete the functor. 01344 delete *i; 01345 t.subscribers[a].erase(i); 01346 return; 01347 } 01348 } 01349 // Not found in the list of subscriptions 01350 throw LogicException("Subscription doesn't exist"); 01351 } 01352 01353 /** Constructor. */ 01354 FunctorInstance(U* u) : instance(u) {} 01355 01356 private: 01357 /** This is the callback method. */ 01358 virtual bool callback(Object* v, const Signal a) const 01359 {return instance ? instance->callback(static_cast<T*>(v),a) : true;} 01360 01361 /** The object whose callback method will be called. */ 01362 U* instance; 01363 }; 01364 01365 01366 // 01367 // UTILITY CLASS "TIMER". 01368 // 01369 01370 /** @brief This class is used to measure the processor time used by the 01371 * program. 01372 * 01373 * The accuracy of the timer is dependent on the implementation of the 01374 * ANSI C-function clock() by your compiler and your platform. 01375 * You may count on milli-second accuracy. Different platforms provide 01376 * more accurate timer functions, which can be used if the accuracy is a 01377 * prime objective.<br> 01378 * When compiled with Visual C++, the timer is returning the elapsed 01379 * time - which is not the expected ANSI behavior!<br> 01380 * Other compilers and platforms return the consumed cpu time, as expected. 01381 * When the load on a machine is low, the consumed cpu-time and the elapsed 01382 * time are close to each other. On a system with a higher load, the 01383 * elapsed time deviates a lot from the consumed cpu-time. 01384 */ 01385 class Timer 01386 { 01387 public: 01388 /** Default constructor. Creating the timer object sets the start point 01389 * for the time measurement. */ 01390 explicit Timer() : start_time(clock()) {} 01391 01392 /** Reset the time counter to 0. */ 01393 void restart() {start_time = clock();} 01394 01395 /** Return the cpu-time in seconds consumed since the creation or the last 01396 * reset of the timer. */ 01397 double elapsed() const {return double(clock()-start_time)/CLOCKS_PER_SEC;} 01398 01399 private: 01400 /** Stores the time when the timer is started. */ 01401 clock_t start_time; 01402 }; 01403 01404 01405 /** Prints a timer to the outputstream. The output is formatted as a double. */ 01406 inline ostream & operator << (ostream& os, const Timer& t) 01407 { 01408 return os << t.elapsed(); 01409 } 01410 01411 01412 // 01413 // UTILITY CLASSES "DATE", "DATE_RANGE" AND "TIME". 01414 // 01415 01416 01417 /** @brief This class represents a time duration with an accuracy of 01418 * one second. 01419 * 01420 * The duration can be both positive and negative. 01421 */ 01422 class TimePeriod 01423 { 01424 friend ostream& operator << (ostream &, const TimePeriod &); 01425 public: 01426 /** Default constructor and constructor with timeperiod passed. */ 01427 TimePeriod(const long l = 0) : lval(l) {} 01428 01429 /** Constructor from a character string.<br> 01430 * See the parse() method for details on the format of the argument. 01431 */ 01432 TimePeriod(const char* s) {parse(s);} 01433 01434 /** Comparison between periods of time. */ 01435 bool operator < (const long& b) const {return lval < b;} 01436 01437 /** Comparison between periods of time. */ 01438 bool operator > (const long& b) const {return lval > b;} 01439 01440 /** Comparison between periods of time. */ 01441 bool operator <= (const long& b) const {return lval <= b;} 01442 01443 /** Comparison between periods of time. */ 01444 bool operator >= (const long& b) const {return lval >= b;} 01445 01446 /** Comparison between periods of time. */ 01447 bool operator < (const TimePeriod& b) const {return lval < b.lval;} 01448 01449 /** Comparison between periods of time. */ 01450 bool operator > (const TimePeriod& b) const {return lval > b.lval;} 01451 01452 /** Comparison between periods of time. */ 01453 bool operator <= (const TimePeriod& b) const {return lval <= b.lval;} 01454 01455 /** Comparison between periods of time. */ 01456 bool operator >= (const TimePeriod& b) const {return lval >= b.lval;} 01457 01458 /** Equality operator. */ 01459 bool operator == (const TimePeriod& b) const {return lval == b.lval;} 01460 01461 /** Inequality operator. */ 01462 bool operator != (const TimePeriod& b) const {return lval != b.lval;} 01463 01464 /** Increase the timeperiod. */ 01465 void operator += (const TimePeriod& l) {lval += l.lval;} 01466 01467 /** Decrease the timeperiod. */ 01468 void operator -= (const TimePeriod& l) {lval -= l.lval;} 01469 01470 /** Returns true of the duration is equal to 0. */ 01471 bool operator ! () const {return lval == 0L;} 01472 01473 /** This conversion operator creates a long value from a timeperiod. */ 01474 operator long() const {return lval;} 01475 01476 /** Converts the date to a string, formatted according to ISO 8601. */ 01477 operator string() const 01478 { 01479 char str[20]; 01480 toCharBuffer(str); 01481 return string(str); 01482 } 01483 01484 /** Function that parses a input string to a time value.<br> 01485 * The string format is following the ISO 8601 specification for 01486 * durations: [-]P[nY][nM][nW][nD][T[nH][nM][nS]]<br> 01487 * Some examples to illustrate how the string is converted to a 01488 * timeperiod, expressed in seconds:<br> 01489 * P1Y = 1 year = 365 days = 31536000 seconds 01490 * P1M = 365/12 days = 2628000 seconds 01491 * P1W = 1 week = 7 days = 604800 seconds 01492 * -P1D = -1 day = -86400 seconds 01493 * PT1H = 1 hour = 3600 seconds 01494 * -PT1000000S = 1000000 seconds 01495 * P1M1WT1H = 1 month + 1 week + 1 hour = 3236400 seconds 01496 * It pretty strictly checks the spec, with a few exceptions: 01497 * - A week field ('W') may coexist with other units. 01498 * - Decimal values are not supported. 01499 * - The alternate format as a date and time is not supported. 01500 */ 01501 DECLARE_EXPORT void parse(const char*); 01502 01503 /** The maximum value for a timeperiod. */ 01504 DECLARE_EXPORT static const TimePeriod MAX; 01505 01506 /** The minimum value for a timeperiod. */ 01507 DECLARE_EXPORT static const TimePeriod MIN; 01508 01509 private: 01510 /** The time is stored as a number of seconds. */ 01511 long lval; 01512 01513 /** This function fills a character buffer with a text representation of 01514 * the TimePeriod.<br> 01515 * The character buffer passed MUST have room for at least 20 characters. 01516 * 20 characters is sufficient for even the most longest possible time 01517 * duration.<br> 01518 * The output format is described with the string() method. 01519 * @see string() 01520 */ 01521 DECLARE_EXPORT void toCharBuffer(char*) const; 01522 }; 01523 01524 01525 /** Prints a Timeperiod to the outputstream. 01526 * @see TimePeriod::string() 01527 */ 01528 inline ostream & operator << (ostream & os, const TimePeriod & t) 01529 { 01530 char str[20]; 01531 t.toCharBuffer(str); 01532 return os << str; 01533 } 01534 01535 01536 /** @brief This class represents a date and time with an accuracy of 01537 * one second. */ 01538 class Date 01539 { 01540 friend ostream& operator << (ostream &, const Date &); 01541 private: 01542 /** This string is a format string to be used to convert a date to and 01543 * from a string format. The formats codes that are allowed are the 01544 * ones recognized by the standard C function strftime: 01545 * - %a short name of day 01546 * - %A full name of day 01547 * - %b short name of month 01548 * - %B full name of month 01549 * - %c standard string for Date and time 01550 * - %d day of month (between 1 and 31) 01551 * - %H hour (between 0 and 23) 01552 * - %I hour (between 1 and 12) 01553 * - %j day of the year (between 1 and 366) 01554 * - %m month as number (between 1 and 12) 01555 * - %M minutes (between 0 and 59) 01556 * - %p AM/PM 01557 * - %S seconds (between o and 59) 01558 * - %U week of the year (between 0 and 52, sunday as start of week) 01559 * - %w day of the week (between 0 and 6, sunday as start of week) 01560 * - %W week of the year (monday as first day of week) 01561 * - %x standard string for Date 01562 * - %X standard string for time 01563 * - %y year (between 0 and 99, without century) 01564 * - %Y year (complete) 01565 * - %Z time zone 01566 * - %% percentage sign 01567 * The default date format is %Y-%m-%dT%H:%M:%S, which is the standard 01568 * format defined in the XML Schema standard. 01569 */ 01570 static DECLARE_EXPORT string format; 01571 01572 /** The internal representation of a date is a single long value. */ 01573 time_t lval; 01574 01575 /** Checks whether we stay within the boundaries of finite Dates. */ 01576 DECLARE_EXPORT void checkFinite(long long); 01577 01578 /** A private constructor used to create the infinitePast and 01579 * infiniteFuture constants. */ 01580 Date(const char* s, bool dummy) {parse(s);} 01581 01582 /** A utility function that uses the C function localtime to compute the 01583 * details of the current time: day of the week, day of the month, 01584 * day of the year, hour, minutes, seconds 01585 */ 01586 inline void getInfo(struct tm* tm_struct) const 01587 { 01588 // The standard library function localtime() is not re-entrant: the same 01589 // static structure is used for all calls. In a multi-threaded environment 01590 // the function is not to be used. 01591 // The POSIX standard defines a re-entrant version of the function: 01592 // localtime_r. 01593 // Visual C++ 6.0 and Borland 5.5 are missing it, but provide a thread-safe 01594 // variant without changing the function semantics. 01595 #ifdef HAVE_LOCALTIME_R 01596 localtime_r(&lval, tm_struct); 01597 #else 01598 *tm_struct = *localtime(&lval); 01599 #endif 01600 } 01601 01602 public: 01603 01604 /** Constructor initialized with a long value. */ 01605 Date(const time_t l) : lval(l) {checkFinite(lval);} 01606 01607 /** Default constructor. */ 01608 // This constructor can skip the check for finite dates, and 01609 // thus gives the best performance. 01610 Date() : lval(infinitePast.lval) {} 01611 01612 /* Note: the automatic copy constructor works fine and is faster than 01613 writing our own. */ 01614 01615 /** Constructor initialized with a string. The string needs to be in 01616 * the format specified by the "format". */ 01617 Date(const char* s) {parse(s); checkFinite(lval);} 01618 01619 /** Constructor with year, month and day as arguments. Hours, minutes 01620 * and seconds can optionally be passed too. 01621 */ 01622 DECLARE_EXPORT Date(int year, int month, int day, 01623 int hr=0, int min=0, int sec=0 01624 ); 01625 01626 /** Comparison between dates. */ 01627 bool operator < (const Date& b) const {return lval < b.lval;} 01628 01629 /** Comparison between dates. */ 01630 bool operator > (const Date& b) const {return lval > b.lval;} 01631 01632 /** Equality of dates. */ 01633 bool operator == (const Date& b) const {return lval == b.lval;} 01634 01635 /** Inequality of dates. */ 01636 bool operator != (const Date& b) const {return lval != b.lval;} 01637 01638 /** Comparison between dates. */ 01639 bool operator >= (const Date& b) const {return lval >= b.lval;} 01640 01641 /** Comparison between dates. */ 01642 bool operator <= (const Date& b) const {return lval <= b.lval;} 01643 01644 /** Assignment operator. */ 01645 void operator = (const Date& b) {lval = b.lval;} 01646 01647 /** Adds some time to this date. */ 01648 void operator += (const TimePeriod& l) 01649 {checkFinite(static_cast<long long>(l) + lval);} 01650 01651 /** Subtracts some time to this date. */ 01652 void operator -= (const TimePeriod& l) 01653 {checkFinite(- static_cast<long long>(l) + lval);} 01654 01655 /** Adding a time to a date returns a new date. */ 01656 Date operator + (const TimePeriod& l) const 01657 { 01658 Date d; 01659 d.checkFinite(static_cast<long long>(l) + lval); 01660 return d; 01661 } 01662 01663 /** Subtracting a time from a date returns a new date. */ 01664 Date operator - (const TimePeriod& l) const 01665 { 01666 Date d; 01667 d.checkFinite(- static_cast<long>(l) + lval); 01668 return d; 01669 } 01670 01671 /** Subtracting two date values returns the time difference in a 01672 * TimePeriod object. */ 01673 TimePeriod operator - (const Date& l) const 01674 {return static_cast<long>(lval - l.lval);} 01675 01676 /** Check whether the date has been initialized. */ 01677 bool operator ! () const {return lval == infinitePast.lval;} 01678 01679 /** Check whether the date has been initialized. */ 01680 operator bool() const {return lval != infinitePast.lval;} 01681 01682 /** Static function returns a date object initialized with the current 01683 * Date and time. */ 01684 static Date now() {return Date(time(0));} 01685 01686 /** Converts the date to a string. The format can be controlled by the 01687 * setFormat() function. */ 01688 operator string() const 01689 { 01690 char str[30]; 01691 toCharBuffer(str); 01692 return string(str); 01693 } 01694 01695 /** This function fills a character buffer with a text representation of 01696 * the date.<br> 01697 * The character buffer passed is expected to have room for 01698 * at least 30 characters. 30 characters should be sufficient for even 01699 * the most funky date format. 01700 */ 01701 size_t toCharBuffer(char* str) const 01702 { 01703 struct tm t; 01704 getInfo(&t); 01705 return strftime(str, 30, format.c_str(), &t); 01706 } 01707 01708 /** Return the seconds since the epoch, which is also the internal 01709 * representation of a date. */ 01710 time_t getTicks() const {return lval;} 01711 01712 /** Function that parses a string according to the format string. */ 01713 DECLARE_EXPORT void parse(const char*, const string& = format); 01714 01715 /** Updates the default date format. */ 01716 static void setFormat(const string& n) {format = n;} 01717 01718 /** Retrieves the default date format. */ 01719 static string getFormat() {return format;} 01720 01721 /** A constant representing the infinite past, i.e. the earliest time which 01722 * we can represent.<br> 01723 * This value is normally 1971-01-01T00:00:00. 01724 */ 01725 static DECLARE_EXPORT const Date infinitePast; 01726 01727 /** A constant representing the infinite future, i.e. the latest time which 01728 * we can represent.<br> 01729 * This value is currently set to 2030-12-31T00:00:00. 01730 */ 01731 static DECLARE_EXPORT const Date infiniteFuture; 01732 01733 /** Return the number of seconds since january 1st. */ 01734 long getSecondsYear() const 01735 { 01736 struct tm t; 01737 getInfo(&t); 01738 return t.tm_yday * 86400 + t.tm_sec + t.tm_min * 60 + t.tm_hour * 3600; 01739 } 01740 01741 /** Return the number of seconds since the start of the month. */ 01742 long getSecondsMonth() const 01743 { 01744 struct tm t; 01745 getInfo(&t); 01746 return (t.tm_mday-1) * 86400 + t.tm_sec + t.tm_min * 60 + t.tm_hour * 3600; 01747 } 01748 01749 /** Return the number of seconds since the start of the week. 01750 * The week is starting on Sunday. 01751 */ 01752 long getSecondsWeek() const 01753 { 01754 struct tm t; 01755 getInfo(&t); 01756 int result = t.tm_wday * 86400 + t.tm_sec + t.tm_min * 60 + t.tm_hour * 3600; 01757 assert(result >= 0 && result < 604800L); 01758 return result; 01759 } 01760 01761 /** Return the number of seconds since the start of the day. */ 01762 long getSecondsDay() const 01763 { 01764 struct tm t; 01765 getInfo(&t); 01766 int result = t.tm_sec + t.tm_min * 60 + t.tm_hour * 3600; 01767 assert(result >= 0 && result < 86400L); 01768 return result; 01769 } 01770 01771 #ifndef HAVE_STRPTIME 01772 private: 01773 DECLARE_EXPORT char* strptime(const char *, const char *, struct tm *); 01774 #endif 01775 }; 01776 01777 01778 /** Prints a date to the outputstream. */ 01779 inline ostream & operator << (ostream & os, const Date & d) 01780 { 01781 char str[30]; 01782 d.toCharBuffer(str); 01783 return os << str; 01784 } 01785 01786 01787 /** @brief This class defines a date-range, i.e. a start-date and end-date pair. 01788 * 01789 * The behavior is such that the start date is considered as included in 01790 * it, but the end date is excluded from it. 01791 * In other words, a daterange is a halfopen date interval: [start,end[<br> 01792 * The start and end dates are always such that the start date is less than 01793 * or equal to the end date. 01794 */ 01795 class DateRange 01796 { 01797 public: 01798 /** Constructor with specified start and end dates.<br> 01799 * If the start date is later than the end date parameter, the 01800 * parameters will be swapped. */ 01801 DateRange(const Date& st, const Date& nd) : start(st), end(nd) 01802 {if(st>nd) {start=nd; end=st;}} 01803 01804 /** Default constructor.<br> 01805 * This will create a daterange covering the complete horizon. 01806 */ 01807 DateRange() : start(Date::infinitePast), end(Date::infiniteFuture) {} 01808 01809 /** Copy constructor. */ 01810 DateRange(const DateRange& n) : start(n.start), end(n.end) {} 01811 01812 /** Returns the start date. */ 01813 const Date& getStart() const {return start;} 01814 01815 /** Updates the start date.<br> 01816 * If the new start date is later than the end date, the end date will 01817 * be set equal to the new start date. 01818 */ 01819 void setStart(const Date& d) {start=d; if(start>end) end=start;} 01820 01821 /** Returns the end date. */ 01822 const Date & getEnd() const {return end;} 01823 01824 /** Updates the end date.<br> 01825 * If the new end date is earlier than the start date, the start date will 01826 * be set equal to the new end date. 01827 */ 01828 void setEnd(const Date& d) {end=d; if(start>end) start=end;} 01829 01830 /** Updates the start and end dates simultaneously. */ 01831 void setStartAndEnd(const Date& st, const Date& nd) 01832 {if (st<nd) {start=st; end=nd;} else {start=nd; end=st;}} 01833 01834 /** Returns the duration of the interval. Note that this number will always 01835 * be greater than or equal to 0, since the end date is always later than 01836 * the start date. 01837 */ 01838 TimePeriod getDuration() const {return end - start;} 01839 01840 /** Equality of date ranges. */ 01841 bool operator == (const DateRange& b) const 01842 {return start==b.start && end==b.end;} 01843 01844 /** Inequality of date ranges. */ 01845 bool operator != (const DateRange& b) const 01846 {return start!=b.start || end!=b.end;} 01847 01848 /** Move the daterange later in time. */ 01849 void operator += (const TimePeriod& l) {start += l; end += l;} 01850 01851 /** Move the daterange earlier in time. */ 01852 void operator -= (const TimePeriod& l) {start -= l; end -= l;} 01853 01854 /** Assignment operator. */ 01855 void operator = (const DateRange& dr) {start = dr.start; end = dr.end;} 01856 01857 /** Return true if two date ranges are overlapping.<br> 01858 * The start point of the first interval is included in the comparison, 01859 * whereas the end point isn't. As a result this method is not 01860 * symmetrical, ie when a.intersect(b) returns true b.intersect(a) is 01861 * not nessarily true. 01862 */ 01863 bool intersect(const DateRange& dr) const 01864 {return dr.start<=end && dr.end>start;} 01865 01866 /** Returns the number of seconds the two dateranges overlap. */ 01867 TimePeriod overlap(const DateRange& dr) const 01868 { 01869 long x = (dr.end<end ? dr.end : end) 01870 - (dr.start>start ? dr.start : start); 01871 return x>0 ? x : 0; 01872 } 01873 01874 /** Returns true if the date passed as argument does fall within the 01875 * daterange. */ 01876 bool within(const Date& d) const {return d>=start && d<end;} 01877 01878 /** Convert the daterange to a string. */ 01879 DECLARE_EXPORT operator string() const; 01880 01881 /** Updates the default seperator. */ 01882 static void setSeparator(const string& n) 01883 { 01884 separator = n; 01885 separatorlength = n.size(); 01886 } 01887 01888 /** Retrieves the default seperator. */ 01889 static const string& getSeparator() {return separator;} 01890 01891 private: 01892 /** Start date of the interval. */ 01893 Date start; 01894 01895 /** End dat of the interval. */ 01896 Date end; 01897 01898 /** Separator to be used when printing this string. */ 01899 static DECLARE_EXPORT string separator; 01900 01901 /** Separator to be used when printing this string. */ 01902 static DECLARE_EXPORT size_t separatorlength; 01903 }; 01904 01905 01906 /** Prints a date range to the outputstream. 01907 * @see DateRange::string() */ 01908 inline ostream & operator << (ostream & os, const DateRange & dr) 01909 { 01910 return os << dr.getStart() << DateRange::getSeparator() << dr.getEnd(); 01911 } 01912 01913 01914 // 01915 // UTILITY CLASSES FOR INPUT AND OUTPUT 01916 // 01917 01918 01919 /** This type is used to define different ways of persisting an object. */ 01920 enum mode 01921 { 01922 /** Write the full object or a reference. If the object is nested more 01923 * than one level deep a reference is written, otherwise the complete 01924 * object is written.<br> 01925 * This mode is the one to be used when dumping all objects to be restored 01926 * later. The other modes can dump too little or too much data. 01927 * Eg: <MODEL NAME="POL" TYPE="a"><FIELD>value</FIELD></MODEL> 01928 */ 01929 DEFAULT = 0, 01930 /** Write only the key fields of the object.<br> 01931 * Eg: <MODEL NAME="POL" TYPE="a"/> 01932 */ 01933 REFERENCE = 1, 01934 /** Write the full object, but without a header line. This method is 01935 * typically used when a subclass calls the write method of its parent 01936 * class.<br> 01937 * Eg: <FIELD>value</FIELD></MODEL> 01938 */ 01939 NOHEADER = 2, 01940 /** Write the full object, with all its fields and a header line.<br> 01941 * Eg: <MODEL NAME="POL" TYPE="a"><FIELD>value</FIELD></MODEL> 01942 */ 01943 FULL = 3 01944 }; 01945 01946 01947 /** @ brief This utility class escapes special characters from a string. 01948 * 01949 * The following characters are replaced: 01950 * - &: replaced with & 01951 * - <: replaced with < 01952 * - >: replaced with > 01953 * - ": replaced with " 01954 * - ': replaced with ' 01955 * - all other characters are left unchanged 01956 * The reverse process of un-escaping the special character sequences is 01957 * taken care of by the Xerces library. 01958 * 01959 * This class works fine with UTF-8 and single-byte encodings, but will 01960 * NOT work with other multibyte encodings (such as UTF-116 or UTF-32). 01961 */ 01962 class XMLEscape 01963 { 01964 friend DECLARE_EXPORT ostream& operator << (ostream&, const XMLEscape&); 01965 private: 01966 const char* data; 01967 public: 01968 XMLEscape(const char* p) {data = p;} 01969 XMLEscape(const string& p) {data = p.c_str();} 01970 }; 01971 01972 01973 /** Prints the escaped value of the string to the outputstream. */ 01974 DECLARE_EXPORT ostream & operator << (ostream&, const XMLEscape&); 01975 01976 01977 /** @brief Base class for writing XML formatted data to an output stream. 01978 * 01979 * Subclasses implement writing to specific stream types, such as files 01980 * and strings. 01981 */ 01982 class XMLOutput 01983 { 01984 protected: 01985 /** Updating the output stream. */ 01986 void setOutput(ostream& o) {m_fp = &o;} 01987 01988 public: 01989 /** This type is used to define different types of output. 01990 * @see STANDARD 01991 * @see PLAN 01992 * @see PLANDETAIL 01993 */ 01994 typedef unsigned short content_type; 01995 01996 /** Constant used to mark standard export for the export. 01997 * The standard export saves just enough information to persist the full 01998 * state of the model as brief as possible. 01999 * @see PLAN 02000 * @see PLANDETAIL 02001 */ 02002 static DECLARE_EXPORT const content_type STANDARD; 02003 02004 /** Constant to mark an export of the standard information plus the plan 02005 * information. In this format, every entity is saved with the details 02006 * on how it is used in the plan.<br> 02007 * E.g. a resource will be saved with a reference to all its loadplans. 02008 * E.g. an operation will be saved with all its operationplans. 02009 * @see STANDARD 02010 * @see PLANDETAIL 02011 */ 02012 static DECLARE_EXPORT const content_type PLAN; 02013 02014 /** Constant to mark an export of the lowest level of plan information. 02015 * In addition to the plan information pegging information is now saved. 02016 * @see STANDARD 02017 * @see PLAN 02018 */ 02019 static DECLARE_EXPORT const content_type PLANDETAIL; 02020 02021 /** Returns which type of export is requested. 02022 * Constants have been defined for each type. 02023 * @see STANDARD 02024 * @see PLAN 02025 * @see PLANDETAIL 02026 */ 02027 content_type getContentType() const {return content;} 02028 02029 /** Specify the type of export. 02030 * @see STANDARD 02031 * @see PLAN 02032 * @see PLANDETAIL 02033 */ 02034 void setContentType(content_type c) {content = c;} 02035 02036 /** Updates the string that is printed as the first line of each XML 02037 * document.<br> 02038 * The default value is: 02039 * <?xml version="1.0" encoding="UTF-8"?> 02040 */ 02041 void setHeaderStart(const string& s) {headerStart = s;} 02042 02043 /** Returns the string that is printed as the first line of each XML 02044 * document. */ 02045 string getHeaderStart() const {return headerStart;} 02046 02047 /** Updates the attributes that are written for the root element of each 02048 * XML document.<br> 02049 * The default value is an empty string. 02050 */ 02051 void setHeaderAtts(const string& s) {headerAtts = s;} 02052 02053 /** Returns the attributes that are written for the root element of each 02054 * XML document. */ 02055 string getHeaderAtts() const {return headerAtts;} 02056 02057 /** Constructor with a given stream. */ 02058 XMLOutput(ostream& os) : m_nIndent(0), numObjects(0), 02059 numParents(0), currentObject(NULL), parentObject(NULL), content(STANDARD), 02060 headerStart("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"), 02061 headerAtts("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"") 02062 {m_fp = &os; indentstring[0] = '\0';} 02063 02064 /** Default constructor. */ 02065 XMLOutput() : m_nIndent(0), numObjects(0), numParents(0), 02066 currentObject(NULL), parentObject(NULL), content(STANDARD), 02067 headerStart("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"), 02068 headerAtts("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"") 02069 {m_fp = &logger; indentstring[0] = '\0';} 02070 02071 /** Start writing a new object. This method will open a new XML-tag.<br> 02072 * Output: <TAG> 02073 */ 02074 void BeginObject(const Keyword& t) 02075 { 02076 *m_fp << indentstring << t.stringElement() << "\n"; 02077 incIndent(); 02078 } 02079 02080 /** Start writing a new object. This method will open a new XML-tag. 02081 * Output: <TAG attributes> 02082 */ 02083 void BeginObject(const Keyword& t, const string& atts) 02084 { 02085 *m_fp << indentstring << t.stringStartElement() << " " << atts << ">\n"; 02086 incIndent(); 02087 } 02088 02089 /** Start writing a new object. This method will open a new XML-tag.<br> 02090 * The user is responsible to assure string values are escaped correctly with the XMLEscape class.<br> 02091 * Output: <TAG TAG1="val1"> 02092 * @see XMLEscape 02093 */ 02094 template <class T> 02095 void BeginObject(const Keyword& t, const Keyword& attr1, const T& val1) 02096 { 02097 *m_fp << indentstring << t.stringStartElement() 02098 << attr1.stringAttribute() << val1 << "\">\n"; 02099 incIndent(); 02100 } 02101 02102 /** Start writing a new object. This method will open a new XML-tag.<br> 02103 * The user is responsible to assure string values are escaped correctly with the XMLEscape class.<br> 02104 * Output: <TAG TAG1="val1" TAG2="val2"> 02105 * @see XMLEscape 02106 */ 02107 template <class T, class U> 02108 void BeginObject(const Keyword& t, const Keyword& attr1, const T& val1, 02109 const Keyword& attr2, const U& val2) 02110 { 02111 *m_fp << indentstring << t.stringStartElement() 02112 << attr1.stringAttribute() << val1 << "\"" 02113 << attr2.stringAttribute() << val2 << "\">\n"; 02114 incIndent(); 02115 } 02116 02117 /** Start writing a new object. This method will open a new XML-tag.<br> 02118 * The user is responsible to assure string values are escaped correctly with the XMLEscape class.<br> 02119 * Output: <TAG TAG1="val1" TAG2="val2" TAG3="val3"> 02120 * @see XMLEscape 02121 */ 02122 template <class T, class U, class V> 02123 void BeginObject(const Keyword& t, const Keyword& attr1, const T& val1, 02124 const Keyword& attr2, const U& val2, 02125 const Keyword& attr3, const V& val3) 02126 { 02127 *m_fp << indentstring << t.stringStartElement() 02128 << attr1.stringAttribute() << val1 << "\"" 02129 << attr2.stringAttribute() << val2 << "\"" 02130 << attr3.stringAttribute() << val3 << "\">\n"; 02131 incIndent(); 02132 } 02133 02134 /** Write the closing tag of this object and decrease the indentation 02135 * level.<br> 02136 * Output: </TAG_T> 02137 */ 02138 void EndObject(const Keyword& t) 02139 { 02140 decIndent(); 02141 *m_fp << indentstring << t.stringEndElement(); 02142 } 02143 02144 /** Write the string to the output. No XML-tags are added, so this method 02145 * is used for passing text straight into the output file. */ 02146 void writeString(const string& c) 02147 { 02148 *m_fp << indentstring << c << "\n"; 02149 } 02150 02151 /** Write an unsigned long value enclosed opening and closing tags.<br> 02152 * Output: <TAG_T>uint</TAG_T> */ 02153 void writeElement(const Keyword& t, const long unsigned int val) 02154 { 02155 *m_fp << indentstring << t.stringElement() << val << t.stringEndElement(); 02156 } 02157 02158 /** Write an integer value enclosed opening and closing tags.<br> 02159 * Output: <TAG_T>integer</TAG_T> */ 02160 void writeElement(const Keyword& t, const int val) 02161 { 02162 *m_fp << indentstring << t.stringElement() << val << t.stringEndElement(); 02163 } 02164 02165 /** Write a double value enclosed opening and closing tags.<br> 02166 * Output: <TAG_T>double</TAG_T> */ 02167 void writeElement(const Keyword& t, const double val) 02168 { 02169 *m_fp << indentstring << t.stringElement() << val << t.stringEndElement(); 02170 } 02171 02172 /** Write a boolean value enclosed opening and closing tags. The boolean 02173 * is written out as the string 'true' or 'false'.<br> 02174 * Output: <TAG_T>true</TAG_T> 02175 */ 02176 void writeElement(const Keyword& t, const bool val) 02177 { 02178 *m_fp << indentstring << t.stringElement() 02179 << (val ? "true" : "false") << t.stringEndElement(); 02180 } 02181 02182 /** Write a string value enclosed opening and closing tags. Special 02183 * characters (i.e. & < > " ' ) are appropriately escaped.<br> 02184 * Output: <TAG_T>val</TAG_T> */ 02185 void writeElement(const Keyword& t, const string& val) 02186 { 02187 if (!val.empty()) 02188 *m_fp << indentstring << t.stringElement() 02189 << XMLEscape(val) << t.stringEndElement(); 02190 } 02191 02192 /** Writes an element with a string attribute.<br> 02193 * Output: <TAG_U TAG_T="string"/> */ 02194 void writeElement(const Keyword& u, const Keyword& t, const string& val) 02195 { 02196 if (val.empty()) 02197 *m_fp << indentstring << u.stringStartElement() << "/>\n"; 02198 else 02199 *m_fp << indentstring << u.stringStartElement() 02200 << t.stringAttribute() << XMLEscape(val) 02201 << "\"/>\n"; 02202 } 02203 02204 /** Writes an element with a long attribute.<br> 02205 * Output: <TAG_U TAG_T="val"/> */ 02206 void writeElement(const Keyword& u, const Keyword& t, const long val) 02207 { 02208 *m_fp << indentstring << u.stringStartElement() 02209 << t.stringAttribute() << val << "\"/>\n"; 02210 } 02211 02212 /** Writes an element with a date attribute.<br> 02213 * Output: <TAG_U TAG_T="val"/> */ 02214 void writeElement(const Keyword& u, const Keyword& t, const Date& val) 02215 { 02216 *m_fp << indentstring << u.stringStartElement() 02217 << t.stringAttribute() << string(val) << "\"/>\n"; 02218 } 02219 02220 /** Writes an element with 2 string attributes.<br> 02221 * Output: <TAG_U TAG_T1="val1" TAG_T2="val2"/> */ 02222 void writeElement(const Keyword& u, const Keyword& t1, const string& val1, 02223 const Keyword& t2, const string& val2) 02224 { 02225 if(val1.empty()) 02226 *m_fp << indentstring << u.stringStartElement() << "/>\n"; 02227 else 02228 *m_fp << indentstring << u.stringStartElement() 02229 << t1.stringAttribute() << XMLEscape(val1.c_str()) << "\"" 02230 << t2.stringAttribute() << XMLEscape(val2.c_str()) 02231 << "\"/>\n"; 02232 } 02233 02234 /** Writes an element with a string and a long attribute.<br> 02235 * Output: <TAG_U TAG_T1="val1" TAG_T2="val2"/> */ 02236 void writeElement(const Keyword& u, const Keyword& t1, unsigned long val1, 02237 const Keyword& t2, const string& val2) 02238 { 02239 *m_fp << indentstring << u.stringStartElement() 02240 << t1.stringAttribute() << val1 << "\"" 02241 << t2.stringAttribute() << XMLEscape(val2.c_str()) 02242 << "\"/>\n"; 02243 } 02244 02245 /** Writes a C-type character string.<br> 02246 * Output: <TAG_T>val</TAG_T> */ 02247 void writeElement(const Keyword& t, const char* val) 02248 { 02249 if (val) 02250 *m_fp << indentstring << t.stringElement() 02251 << XMLEscape(val) << t.stringEndElement(); 02252 } 02253 02254 /** Writes an timeperiod element.<br> 02255 * Output: <TAG_T>d</TAG_T> /> */ 02256 void writeElement(const Keyword& t, const TimePeriod d) 02257 { 02258 *m_fp << indentstring << t.stringElement() << d << t.stringEndElement(); 02259 } 02260 02261 /** Writes an date element.<br> 02262 * Output: <TAG_T>d</TAG_T> /> */ 02263 void writeElement(const Keyword& t, const Date d) 02264 { 02265 *m_fp << indentstring << t.stringElement() << d << t.stringEndElement(); 02266 } 02267 02268 /** Writes an daterange element.<br> 02269 * Output: <TAG_T>d</TAG_T> */ 02270 void writeElement(const Keyword& t, const DateRange& d) 02271 { 02272 *m_fp << indentstring << t.stringElement() << d << t.stringEndElement(); 02273 } 02274 02275 /** This method writes a serializable object. It maintains a STL-map of 02276 * all objects that have been saved already. For objects that have 02277 * already been saved earlier, the method will instruct the serializable 02278 * object to write only a reference, rather than the complete object. 02279 * You should call this method for all objects in your xml document, 02280 * except for the root object. 02281 * @see writeElementWithHeader(const Keyword&, Object*) 02282 */ 02283 DECLARE_EXPORT void writeElement(const Keyword&, const Object*, mode = DEFAULT); 02284 02285 /** @see writeElement(const Keyword&, const Object*, mode) */ 02286 void writeElement(const Keyword& t, const Object& o, mode m = DEFAULT) 02287 {writeElement(t,&o,m);} 02288 02289 /** This method writes a serializable object with a complete XML compliant 02290 * header.<br> 02291 * You should call this method for the root object of your xml document, 02292 * and writeElement for all objects nested in it. 02293 * @see writeElement(const Keyword&, Object*) 02294 * @see writeHeader 02295 * @exception RuntimeException Generated when multiple root elements 02296 * are available for the output document. 02297 */ 02298 DECLARE_EXPORT void writeElementWithHeader(const Keyword& tag, const Object* object); 02299 02300 /** This method writes the opening tag for an XML output.<br> 02301 * You should call this method or writeElementWithHeader() when writing 02302 * the first element of an xml document. 02303 * @see writeElementWithHeader 02304 * @exception RuntimeException Generated when multiple root elements 02305 * are available for the output document. 02306 */ 02307 DECLARE_EXPORT void writeHeader(const Keyword& tag); 02308 02309 /** Returns a pointer to the object that is currently being saved. */ 02310 Object* getCurrentObject() const 02311 {return const_cast<Object*>(currentObject);} 02312 02313 /** Returns a pointer to the parent of the object that is being saved. */ 02314 Object* getPreviousObject() const 02315 {return const_cast<Object*>(parentObject);} 02316 02317 /** Returns the number of objects that have been serialized. */ 02318 unsigned long countObjects() const {return numObjects;} 02319 02320 private: 02321 /** Output stream. */ 02322 ostream* m_fp; 02323 02324 /** This variable keeps track of the indentation level. 02325 * @see incIndent, decIndent 02326 */ 02327 short int m_nIndent; 02328 02329 /** This string is a null terminated string containing as many spaces as 02330 * indicated by the m_indent. 02331 * @see incIndent, decIndent 02332 */ 02333 char indentstring[41]; 02334 02335 /** Keep track of the number of objects being stored. */ 02336 unsigned long numObjects; 02337 02338 /** Keep track of the number of objects currently in the save stack. */ 02339 unsigned int numParents; 02340 02341 /** This stores a pointer to the object that is currently being saved. */ 02342 const Object *currentObject; 02343 02344 /** This stores a pointer to the object that has previously been saved. */ 02345 const Object *parentObject; 02346 02347 /** Increase the indentation level. The indentation level is between 02348 * 0 and 40. */ 02349 DECLARE_EXPORT void incIndent(); 02350 02351 /** Decrease the indentation level. */ 02352 DECLARE_EXPORT void decIndent(); 02353 02354 /** Stores the type of data to be exported. */ 02355 content_type content; 02356 02357 /** This string defines what will be printed at the start of each XML 02358 * document. The default value is: 02359 * <?xml version="1.0" encoding="UTF-8"?> 02360 */ 02361 string headerStart; 02362 02363 /** This string defines what will be attributes are printed for the root 02364 * element of each XML document. 02365 * The default value is: 02366 * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 02367 */ 02368 string headerAtts; 02369 }; 02370 02371 02372 /** @brief This class writes XML data to a flat file. 02373 * 02374 * Note that an object of this class can write only to a single file. If 02375 * multiple files are required multiple XMLOutputFile objects will be 02376 * required too. 02377 * @see XMLOutput 02378 */ 02379 class XMLOutputFile : public XMLOutput 02380 { 02381 public: 02382 /** Constructor with a filename as argument. An exception will be 02383 * thrown if the output file can't be properly initialized. */ 02384 XMLOutputFile(const string& chFilename) 02385 { 02386 of.open(chFilename.c_str(), ios::out); 02387 if(!of) throw RuntimeException("Could not open output file"); 02388 setOutput(of); 02389 } 02390 02391 /** Destructor. */ 02392 ~XMLOutputFile() {of.close();} 02393 02394 private: 02395 ofstream of; 02396 }; 02397 02398 02399 /** @brief This class writes XML data to a string. 02400 * 02401 * The generated output is stored internally in the class, and can be 02402 * accessed by converting the XMLOutputString object to a string object. 02403 * This class can consume a lot of memory if large sets of objects are 02404 * being saved in this way. 02405 * @see XMLOutput 02406 */ 02407 class XMLOutputString : public XMLOutput 02408 { 02409 public: 02410 /** Constructor with a starting string as argument. */ 02411 XMLOutputString(const string& str) : os(str) {setOutput(os);} 02412 02413 /** Default constructor. */ 02414 XMLOutputString() {setOutput(os);} 02415 02416 /** Return the output string. */ 02417 const string getData() const {return os.str();} 02418 02419 private: 02420 ostringstream os; 02421 }; 02422 02423 02424 /** @brief A class to model keyword instances. 02425 * 02426 * The class uses hashes to do a fast comparison with the set of keywords. 02427 */ 02428 class Attribute 02429 { 02430 private: 02431 /** This string stores the hash value of the element. */ 02432 hashtype hash; 02433 02434 /** A pointer to the string representation of the keyword.<br> 02435 * The string buffer is to be managed by the code creating this 02436 * instance. 02437 */ 02438 const char* ch; 02439 02440 public: 02441 /** Default constructor. */ 02442 explicit Attribute() : hash(0), ch(NULL) {} 02443 02444 /** Constructor. */ 02445 explicit Attribute(const string& n) 02446 : hash(Keyword::hash(n)), ch(n.c_str()) {} 02447 02448 /** Constructor. */ 02449 explicit Attribute(const char* c) : hash(Keyword::hash(c)), ch(c) {} 02450 02451 /** Copy constructor. */ 02452 Attribute(const Attribute& o) : hash(o.hash), ch(o.ch) {} 02453 02454 /** Returns the hash value of this tag. */ 02455 hashtype getHash() const {return hash;} 02456 02457 /** Returns this tag. */ 02458 void reset(const char *const c) 02459 { 02460 hash = Keyword::hash(c); 02461 ch = c; 02462 } 02463 02464 /** Returns this tag. */ 02465 void reset(const XMLCh *const c) 02466 { 02467 hash = Keyword::hash(c); 02468 // An XMLCh is normally a wchar, and would need to be transcoded 02469 // to a char. We won't bother... 02470 ch = NULL; 02471 } 02472 02473 /** Return the element name. Since this method involves a lookup in a 02474 * table with Keywords, it has some performance impact and should be 02475 * avoided where possible. Only the hash of an element can efficiently 02476 * be retrieved. 02477 */ 02478 DECLARE_EXPORT const char* getName() const; 02479 02480 /** Returns true when this element is an instance of this tag. This method 02481 * doesn't involve a string comparison and is extremely efficient. */ 02482 bool isA(const Keyword& t) const {return t.getHash() == hash;} 02483 02484 /** Returns true when this element is an instance of this tag. This method 02485 * doesn't involve a string comparison and is extremely efficient. */ 02486 bool isA(const Keyword* t) const {return t->getHash() == hash;} 02487 02488 /** Comparison operator. */ 02489 bool operator < (const Attribute& o) const {return hash < o.hash;} 02490 02491 /** String comparison. */ 02492 bool operator == (const string o) const {return o == ch;} 02493 }; 02494 02495 02496 /** @brief This abstract class represents a attribute and value pair for 02497 * updating objects in frePPLe. 02498 * 02499 * It is instantiated in the XMLElement and PythonObject classes. 02500 * @todo only takes care of transformation from external format to C++. Not the C++ to external format yet. 02501 */ 02502 class DataElement 02503 { 02504 public: 02505 virtual operator bool() const 02506 {throw LogicException("DataElement is an abstract class");} 02507 02508 /** Destructor. */ 02509 virtual ~DataElement() {} 02510 02511 void operator >> (unsigned long int& val) const {val = getUnsignedLong();} 02512 02513 void operator >> (long& val) const {val = getLong();} 02514 02515 void operator >> (TimePeriod& val) const {val = getTimeperiod();} 02516 02517 void operator >> (bool& v) const {v=getBool();} 02518 02519 void operator >> (int& val) const {val = getInt();} 02520 02521 void operator >> (double& val) const {val = getDouble();} 02522 02523 void operator >> (Date& val) const {val = getDate();} 02524 02525 void operator >> (string& val) const {val = getString();} 02526 02527 virtual long getLong() const 02528 {throw LogicException("DataElement is an abstract class");} 02529 02530 virtual unsigned long getUnsignedLong() const 02531 {throw LogicException("DataElement is an abstract class");} 02532 02533 virtual TimePeriod getTimeperiod() const 02534 {throw LogicException("DataElement is an abstract class");} 02535 02536 virtual int getInt() const 02537 {throw LogicException("DataElement is an abstract class");} 02538 02539 virtual double getDouble() const 02540 {throw LogicException("DataElement is an abstract class");} 02541 02542 virtual Date getDate() const 02543 {throw LogicException("DataElement is an abstract class");} 02544 02545 virtual string getString() const 02546 {throw LogicException("DataElement is an abstract class");} 02547 02548 virtual bool getBool() const 02549 {throw LogicException("DataElement is an abstract class");} 02550 }; 02551 02552 02553 /** @brief This class represents an XML element being read in from the 02554 * input file. */ 02555 class XMLElement : public DataElement 02556 { 02557 private: 02558 /** This string stores the XML input data. */ 02559 string m_strData; 02560 02561 public: 02562 virtual operator bool() const {return !m_strData.empty();} 02563 02564 /** Default constructor. */ 02565 XMLElement() {} 02566 02567 /** Constructor. */ 02568 XMLElement(const string& v) : m_strData(v) {} 02569 02570 /** Destructor. */ 02571 virtual ~XMLElement() {} 02572 02573 /** Re-initializes an existing element. Using this method we can avoid 02574 * destroying and recreating XMLelement objects too frequently. Instead 02575 * we can manage them in a array. 02576 */ 02577 void reset() {m_strData.clear();} 02578 02579 /** Add some characters to this data field of this element.<br> 02580 * The second argument is the number of bytes, not the number of 02581 * characters. 02582 */ 02583 void addData(const char *pData, size_t len) {m_strData.append(pData,len);} 02584 02585 /** Set the data value of this element. */ 02586 void setData(const char *pData) {m_strData.assign(pData);} 02587 02588 /** Return the data field. */ 02589 const char *getData() const {return m_strData.c_str();} 02590 02591 virtual long getLong() const {return atol(getData());} 02592 02593 virtual unsigned long getUnsignedLong() const {return atol(getData());} 02594 02595 virtual TimePeriod getTimeperiod() const {return TimePeriod(getData());} 02596 02597 virtual int getInt() const {return atoi(getData());} 02598 02599 virtual double getDouble() const {return atof(getData());} 02600 02601 virtual Date getDate() const {return Date(getData());} 02602 02603 /** Returns the string value of the XML data. The xerces library takes care 02604 * of appropriately unescaping special character sequences. */ 02605 virtual string getString() const {return m_strData;} 02606 02607 /** Interprets the element as a boolean value.<br> 02608 * <p>Our implementation is a bit more generous and forgiving than the 02609 * boolean datatype that is part of the XML schema v2 standard. 02610 * The standard expects the following literals:<br> 02611 * {true, false, 1, 0}</p> 02612 * <p>Our implementation uses only the first charater of the text, and is 02613 * case insensitive. It thus matches a wider range of values:<br> 02614 * {t.*, T.*, f.*, F.*, 1.*, 0.*}</p> 02615 */ 02616 DECLARE_EXPORT bool getBool() const; 02617 }; 02618 02619 02620 /** @brief This class groups some functions used to interact with the operating 02621 * system environment. 02622 * 02623 * It handles: 02624 * - The location of the configuration files. 02625 * - The maximum number of processors / threads to be used by frePPLe. 02626 * - An output stream for logging all output. 02627 * - Dynamic loading of a shared library. 02628 */ 02629 class Environment 02630 { 02631 private: 02632 /** Caches the number of processor cores. */ 02633 static DECLARE_EXPORT int processorcores; 02634 02635 /** A file where output is directed to. */ 02636 static DECLARE_EXPORT ofstream logfile; 02637 02638 /** The name of the log file. */ 02639 static DECLARE_EXPORT string logfilename; 02640 02641 /** A list of all loaded modules. */ 02642 static DECLARE_EXPORT set<string> moduleRegistry; 02643 02644 public: 02645 /** Search for a file with a given name.<br> 02646 * The following directories are searched in sequence to find a match: 02647 * - The current directory. 02648 * - The directory referred to by the variable FREPPLE_HOME, if it 02649 * is defined. 02650 * - The data directory as configured during the compilation. 02651 * This applies only to linux / unix. 02652 * - The library directory as configured during the compilation. 02653 * This applies only to linux / unix. 02654 */ 02655 static DECLARE_EXPORT string searchFile(const string); 02656 02657 /** Returns the number of processor cores on your machine. */ 02658 static DECLARE_EXPORT int getProcessorCores(); 02659 02660 /** Returns the name of the logfile. */ 02661 static const string& getLogFile() {return logfilename;} 02662 02663 /** Updates the filename for logging error messages and warnings. 02664 * The file is also opened for writing and the standard output and 02665 * standard error output streams are redirected to it.<br> 02666 * If the filename starts with '+' the log file is appended to 02667 * instead of being overwritten. 02668 */ 02669 static DECLARE_EXPORT void setLogFile(const string& x); 02670 02671 /** Type for storing parameters passed to a module that is loaded. */ 02672 typedef map<string,XMLElement> ParameterList; 02673 02674 /** @brief Function to dynamically load a shared library in frePPLe. 02675 * 02676 * After loading the library, the function "initialize" of the module 02677 * is executed. 02678 * 02679 * The current implementation supports the following platforms: 02680 * - Windows 02681 * - Linux 02682 * - Unix systems supporting the dlopen function in the standard way. 02683 * Some unix systems have other or deviating APIs. A pretty messy story :-< 02684 */ 02685 static DECLARE_EXPORT void loadModule(string lib, ParameterList& parameters); //@todo replace argument with a AttributeList instead 02686 02687 /** Print all modules that have been loaded. */ 02688 static DECLARE_EXPORT void printModules(); 02689 }; 02690 02691 02692 /** @brief This class handles two-way translation between the data types 02693 * in C++ and Python. 02694 * 02695 * This class is basically a wrapper around a PyObject pointer. 02696 * 02697 * When creating a PythonObject from a C++ object, make sure to increment 02698 * the reference count of the object.<br> 02699 * When constructing a PythonObject from an existing Python object, the 02700 * code that provided us the PyObject pointer should have incremented the 02701 * reference count already. 02702 * 02703 * @todo endelement function should be shared with setattro function. 02704 * Unifies the python and xml worlds: shared code base to update objects! 02705 * (Code for extracting info is still python specific, and writeElement 02706 * is also xml-specific) 02707 * xml->prevObject = python->cast value to a different type 02708 * 02709 * @todo object creator should be common with the XML reader, which uses 02710 * the registered factory method. 02711 * Also supports add/add_change/remove. 02712 * Tricky: flow/load which use an additional validate() method 02713 */ 02714 class PythonObject : public DataElement 02715 { 02716 private: 02717 PyObject* obj; 02718 02719 public: 02720 /** Default constructor. The default value is equal to Py_None. */ 02721 explicit PythonObject() : obj(Py_None) {Py_INCREF(obj);} 02722 02723 /** Constructor from an existing Python object.<br> 02724 * The reference count isn't increased. 02725 */ 02726 PythonObject(const PyObject* o) 02727 : obj(o ? const_cast<PyObject*>(o) : Py_None) {Py_INCREF(obj);} 02728 02729 /** This conversion operator casts the object back to a PyObject pointer. */ 02730 operator PyObject*() const {return obj;} 02731 02732 /** Check for null value. */ 02733 operator bool() const {return obj != NULL && obj != Py_None;} 02734 02735 /** Assignment operator. */ 02736 PythonObject& operator = (const PythonObject& o) 02737 { 02738 if (obj) {Py_DECREF(obj);} 02739 obj = o.obj; 02740 if (obj) {Py_INCREF(obj);} 02741 return *this; 02742 } 02743 02744 /** Check whether the Python object is of a certain type.<br> 02745 * Subclasses of the argument type will also give a true return value. 02746 */ 02747 bool check(const MetaClass* c) const 02748 { 02749 return obj ? 02750 PyObject_TypeCheck(obj, c->pythonClass) : 02751 false; 02752 } 02753 02754 /** Check whether the Python object is of a certain type.<br> 02755 * Subclasses of the argument type will also give a true return value. 02756 */ 02757 bool check(const PythonType& c) const 02758 { 02759 return obj ? 02760 PyObject_TypeCheck(obj, c.type_object()) : 02761 false; 02762 } 02763 02764 /** Convert a Python string into a C++ string. */ 02765 inline string getString() const 02766 { 02767 if (obj == Py_None) 02768 return string(); 02769 else if (PyUnicode_Check(obj)) 02770 { 02771 // It's a Python unicode string 02772 PyObject* x = PyUnicode_AsEncodedString(obj, 02773 PythonInterpreter::getPythonEncoding(), "ignore"); 02774 string result = PyString_AsString(x); 02775 Py_DECREF(x); 02776 return result; 02777 } 02778 else if (PyString_Check(obj)) 02779 // It's a Python string 02780 return PyString_AsString(obj); 02781 else 02782 { 02783 // It's not a Python string object, call the str() function on the object 02784 PyObject* x = PyObject_Str(obj); 02785 string result = PyString_AsString(x); 02786 Py_DECREF(x); 02787 return result; 02788 } 02789 } 02790 02791 /** Extract an unsigned long from the Python object. */ 02792 unsigned long getUnsignedLong() const 02793 { 02794 if (obj == Py_None) return 0; 02795 if (PyString_Check(obj)) 02796 { 02797 PyObject* t = PyFloat_FromString(obj, NULL); 02798 if (!t) throw DataException("Invalid number"); 02799 double x = PyFloat_AS_DOUBLE(t); 02800 Py_DECREF(t); 02801 if (x < 0 || x > ULONG_MAX) 02802 throw DataException("Invalid number"); 02803 return static_cast<unsigned long>(x); 02804 } 02805 return PyLong_AsUnsignedLong(obj); 02806 } 02807 02808 /** Convert a Python datetime.date or datetime.datetime object into a 02809 * frePPLe date. */ 02810 DECLARE_EXPORT Date getDate() const; 02811 02812 /** Convert a Python number or string into a C++ double. */ 02813 inline double getDouble() const 02814 { 02815 if (obj == Py_None) return 0; 02816 if (PyString_Check(obj)) 02817 { 02818 PyObject* t = PyFloat_FromString(obj, NULL); 02819 if (!t) throw DataException("Invalid number"); 02820 double x = PyFloat_AS_DOUBLE(t); 02821 Py_DECREF(t); 02822 return x; 02823 } 02824 return PyFloat_AsDouble(obj); 02825 } 02826 02827 /** Convert a Python number or string into a C++ integer. */ 02828 inline int getInt() const 02829 { 02830 if (PyString_Check(obj)) 02831 { 02832 PyObject* t = PyFloat_FromString(obj, NULL); 02833 if (!t) throw DataException("Invalid number"); 02834 double x = PyFloat_AS_DOUBLE(t); 02835 Py_DECREF(t); 02836 if (x < INT_MIN || x > INT_MAX) 02837 throw DataException("Invalid number"); 02838 return static_cast<int>(x); 02839 } 02840 int result = PyInt_AsLong(obj); 02841 if (result == -1 && PyErr_Occurred()) 02842 throw DataException("Invalid number"); 02843 return result; 02844 } 02845 02846 /** Convert a Python number into a C++ long. */ 02847 inline long getLong() const 02848 { 02849 if (PyString_Check(obj)) 02850 { 02851 PyObject* t = PyFloat_FromString(obj, NULL); 02852 if (!t) throw DataException("Invalid number"); 02853 double x = PyFloat_AS_DOUBLE(t); 02854 Py_DECREF(t); 02855 if (x < LONG_MIN || x > LONG_MIN) 02856 throw DataException("Invalid number"); 02857 return static_cast<long>(x); 02858 } 02859 int result = PyInt_AsLong(obj); 02860 if (result == -1 && PyErr_Occurred()) 02861 throw DataException("Invalid number"); 02862 return result; 02863 } 02864 02865 /** Convert a Python number into a C++ bool. */ 02866 inline bool getBool() const 02867 { 02868 return PyObject_IsTrue(obj) ? true : false; 02869 } 02870 02871 /** Convert a Python number as a number of seconds into a frePPLe 02872 * TimePeriod.<br> 02873 * A TimePeriod is represented as a number of seconds in Python. 02874 */ 02875 TimePeriod getTimeperiod() const 02876 { 02877 if (PyString_Check(obj)) 02878 { 02879 if (PyUnicode_Check(obj)) 02880 { 02881 // Replace the unicode object with a string encoded in the correct locale 02882 const_cast<PyObject*&>(obj) = 02883 PyUnicode_AsEncodedString(obj, PythonInterpreter::getPythonEncoding(), "ignore"); 02884 } 02885 return TimePeriod(PyString_AsString(PyObject_Str(obj))); 02886 } 02887 int result = PyInt_AsLong(obj); 02888 if (result == -1 && PyErr_Occurred()) 02889 throw DataException("Invalid number"); 02890 return result; 02891 } 02892 02893 /** Constructor from a pointer to an Object.<br> 02894 * The metadata of the Object instances allow us to create a Python 02895 * object that works as a proxy for the C++ object. 02896 */ 02897 DECLARE_EXPORT PythonObject(Object* p); 02898 02899 /** Convert a C++ string into a (raw) Python string. */ 02900 inline PythonObject(const string& val) 02901 { 02902 if (val.empty()) 02903 { 02904 obj = Py_None; 02905 Py_INCREF(obj); 02906 } 02907 else 02908 obj = PyString_FromString(val.c_str()); 02909 } 02910 02911 /** Convert a C++ double into a Python number. */ 02912 inline PythonObject(const double val) 02913 { 02914 obj = PyFloat_FromDouble(val); 02915 } 02916 02917 /** Convert a C++ integer into a Python integer. */ 02918 inline PythonObject(const int val) 02919 { 02920 obj = PyInt_FromLong(val); 02921 } 02922 02923 /** Convert a C++ long into a Python long. */ 02924 inline PythonObject(const long val) 02925 { 02926 obj = PyLong_FromLong(val); 02927 } 02928 02929 /** Convert a C++ unsigned long into a Python long. */ 02930 inline PythonObject(const unsigned long val) 02931 { 02932 obj = PyLong_FromUnsignedLong(val); 02933 } 02934 02935 /** Convert a C++ boolean into a Python boolean. */ 02936 inline PythonObject(const bool val) 02937 { 02938 obj = val ? Py_True : Py_False; 02939 Py_INCREF(obj); 02940 } 02941 02942 /** Convert a frePPLe TimePeriod into a Python number representing 02943 * the number of seconds. */ 02944 inline PythonObject(const TimePeriod val) 02945 { 02946 // A TimePeriod is represented as a number of seconds in Python 02947 obj = PyLong_FromLong(val); 02948 } 02949 02950 /** Convert a frePPLe date into a Python datetime.datetime object. */ 02951 DECLARE_EXPORT PythonObject(const Date& val); 02952 }; 02953 02954 02955 /** @brief This call is a wrapper around a Python function that can be 02956 * called from the C++ code. 02957 */ 02958 class PythonFunction : public PythonObject 02959 { 02960 public: 02961 /** Default constructor. */ 02962 PythonFunction() : func(NULL) {} 02963 02964 /** Constructor. */ 02965 DECLARE_EXPORT PythonFunction(const string&); 02966 02967 /** Constructor. */ 02968 DECLARE_EXPORT PythonFunction(PyObject*); 02969 02970 /** Copy constructor. */ 02971 PythonFunction(const PythonFunction& o) : func(o.func) 02972 { 02973 if (func) {Py_INCREF(func);} 02974 } 02975 02976 /** Assignment operator. */ 02977 PythonFunction& operator= (const PythonFunction& o) 02978 { 02979 if (func) {Py_DECREF(func);} 02980 func = o.func; 02981 if (func) {Py_INCREF(func);} 02982 return *this; 02983 } 02984 02985 /** Destructor. */ 02986 ~PythonFunction() {if (func) {Py_DECREF(func);}} 02987 02988 /** Conversion operator to a Python pointer. */ 02989 operator const PyObject*() const {return func;} 02990 02991 /** Conversion operator to a string. */ 02992 operator string() const {return func ? PyEval_GetFuncName(func) : "NULL";} 02993 02994 /** Conversion operator to bool. */ 02995 operator bool() const {return func != NULL;} 02996 02997 /** Call the Python function without arguments. */ 02998 DECLARE_EXPORT PythonObject call() const; 02999 03000 /** Call the Python function with one argument. */ 03001 DECLARE_EXPORT PythonObject call(const PyObject*) const; 03002 03003 /** Call the Python function with two arguments. */ 03004 DECLARE_EXPORT PythonObject call(const PyObject*, const PyObject*) const; 03005 03006 private: 03007 /** A pointer to the Python object. */ 03008 PyObject* func; 03009 }; 03010 03011 03012 /** @brief This class represents a dictionary of keyword + value pairs. 03013 * 03014 * This abstract class can be instantiated as XML attributes, or as a 03015 * Python keyword dictionary. 03016 * - XML:<br> 03017 * <buffer name="a" onhand="10" category="A" /> 03018 * - Python:<br> 03019 * buffer(name="a", onhand="10", category="A") 03020 */ 03021 class AttributeList 03022 { 03023 public: 03024 virtual const DataElement* get(const Keyword&) const = 0; 03025 // @todo Iterator??? 03026 03027 /** Destructor. */ 03028 virtual ~AttributeList() {} 03029 }; 03030 03031 03032 /** @brief This class represents a list of XML attributes. */ 03033 class XMLAttributeList : public AttributeList 03034 { 03035 private: 03036 const xercesc::Attributes* atts; 03037 XMLElement result; 03038 public: 03039 XMLAttributeList(const xercesc::Attributes* a) : atts(a) {} 03040 03041 const XMLElement* get(const Keyword& key) const 03042 { 03043 char* s = xercesc::XMLString::transcode(atts->getValue(key.getXMLCharacters())); 03044 const_cast<XMLAttributeList*>(this)->result.setData(s ? s : ""); 03045 xercesc::XMLString::release(&s); 03046 return &result; 03047 } 03048 }; 03049 03050 03051 /** @brief This class is a wrapper around a Python dictionary. */ 03052 class PythonAttributeList : public AttributeList 03053 { 03054 private: 03055 PyObject* kwds; 03056 PythonObject result; 03057 03058 public: 03059 PythonAttributeList(PyObject* a) : kwds(a) {} 03060 03061 virtual const DataElement* get(const Keyword& k) const 03062 { 03063 if (!kwds) 03064 { 03065 const_cast<PythonAttributeList*>(this)->result = PythonObject(); 03066 return &result; 03067 } 03068 PyObject* val = PyDict_GetItemString(kwds,k.getName().c_str()); 03069 const_cast<PythonAttributeList*>(this)->result = PythonObject(val); 03070 return &result; 03071 } 03072 }; 03073 03074 03075 /** @brief This is a base class for all Python extension types. 03076 * 03077 * When creating you own extensions, inherit from the PythonExtension 03078 * template class instead of this one. 03079 * 03080 * It inherits from the PyObject C struct, defined in the Python C API.<br> 03081 * These functions aren't called directly from Python. Python first calls a 03082 * handler C-function and the handler function will use a virtual call to 03083 * run the correct C++-method. 03084 * 03085 * Our extensions don't use the usual Python heap allocator. They are 03086 * created and initialized with the regular C++ new and delete. A special 03087 * deallocator is called from Python to delete objects when their reference 03088 * count reaches zero. 03089 */ 03090 class PythonExtensionBase : public PyObject 03091 { 03092 public: 03093 /** Default constructor */ 03094 PythonExtensionBase() {} 03095 03096 /** Destructor. */ 03097 virtual ~PythonExtensionBase() 03098 { 03099 if (PyObject::ob_refcnt > 1) 03100 logger << "Warning: Deleting " << PyObject::ob_type->tp_name 03101 << " object that is still referenced " 03102 << (PyObject::ob_refcnt-1) << " times" << endl; 03103 } 03104 03105 /** A function to force an object to be destroyed by the Python garbage 03106 * collection.<br> 03107 * Be very careful to use this! 03108 */ 03109 void resetReferenceCount() {PyObject::ob_refcnt = 0;} 03110 03111 /** Initialize the object to a certain Python type. */ 03112 inline void initType(const MetaClass *t) 03113 { 03114 PyObject_INIT(this,t->pythonClass); 03115 } 03116 03117 /** Initialize the object to a certain Python type. */ 03118 inline void initType(PyTypeObject *t) 03119 { 03120 PyObject_INIT(this,t); 03121 } 03122 03123 /** Default getattro method. <br> 03124 * Subclasses are expected to implement an override if the type supports 03125 * gettattro. 03126 */ 03127 virtual PyObject* getattro(const Attribute& attr) 03128 { 03129 PyErr_SetString(PythonLogicException, "Missing method 'getattro'"); 03130 return NULL; 03131 } 03132 03133 /** Default setattro method. <br> 03134 * Subclasses are expected to implement an override if the type supports 03135 * settattro. 03136 */ 03137 virtual int setattro(const Attribute& attr, const PythonObject& field) 03138 { 03139 PyErr_SetString(PythonLogicException, "Missing method 'setattro'"); 03140 return -1; 03141 } 03142 03143 /** Default compare method. <br> 03144 * Subclasses are expected to implement an override if the type supports 03145 * compare. 03146 */ 03147 virtual int compare(const PyObject* other) const 03148 { 03149 PyErr_SetString(PythonLogicException, "Missing method 'compare'"); 03150 return -1; 03151 } 03152 03153 /** Default iternext method. <br> 03154 * Subclasses are expected to implement an override if the type supports 03155 * iteration. 03156 */ 03157 virtual PyObject* iternext() 03158 { 03159 PyErr_SetString(PythonLogicException, "Missing method 'iternext'"); 03160 return NULL; 03161 } 03162 03163 /** Default call method. <br> 03164 * Subclasses are expected to implement an override if the type supports 03165 * calls. 03166 */ 03167 virtual PyObject* call(const PythonObject& args, const PythonObject& kwds) 03168 { 03169 PyErr_SetString(PythonLogicException, "Missing method 'call'"); 03170 return NULL; 03171 } 03172 03173 /** Default str method. <br> 03174 * Subclasses are expected to implement an override if the type supports 03175 * conversion to a string. 03176 */ 03177 virtual PyObject* str() const 03178 { 03179 PyErr_SetString(PythonLogicException, "Missing method 'str'"); 03180 return NULL; 03181 } 03182 03183 protected: 03184 static vector<PythonType*> table; 03185 03186 DECLARE_EXPORT static PythonType* registerPythonType(int, const type_info*); 03187 03188 }; 03189 03190 03191 /** @brief Template class to define Python extensions. 03192 * 03193 * The template argument should be your extension class, inheriting from 03194 * this template class: 03195 * class MyClass : PythonExtension<MyClass> 03196 * 03197 * The structure of the C++ wrappers around the C Python API is heavily 03198 * inspired on the design of PyCXX.<br> 03199 * More information can be found on http://cxx.sourceforge.net 03200 */ 03201 template<class T> 03202 class PythonExtension: public PythonExtensionBase, public NonCopyable 03203 { 03204 public: 03205 /** Constructor.<br> 03206 * The Python metadata fields always need to be set correctly. 03207 */ 03208 explicit PythonExtension() 03209 { 03210 PyObject_Init(this, getType().type_object()); 03211 } 03212 03213 /** Destructor. */ 03214 virtual ~PythonExtension() {} 03215 03216 /** This method keeps the type information object for your extension. */ 03217 static PythonType& getType() 03218 { 03219 static PythonType* cachedTypePtr = NULL; 03220 if (cachedTypePtr) return *cachedTypePtr; 03221 03222 // Register a new type 03223 cachedTypePtr = registerPythonType(sizeof(T), &typeid(T)); 03224 03225 // Using our own memory deallocator 03226 cachedTypePtr->supportdealloc( deallocator ); 03227 03228 return *cachedTypePtr; 03229 } 03230 03231 /** Free the memory.<br> 03232 * See the note on the memory management in the class documentation 03233 * for PythonExtensionBase. 03234 */ 03235 static void deallocator(PyObject* o) {delete static_cast<T*>(o);} 03236 }; 03237 03238 03239 /** @brief Object is the abstract base class for the main entities. 03240 * 03241 * It handles to following capabilities: 03242 * - <b>Metadata:</b> All subclasses publish metadata about their structure. 03243 * - <b>Python object:</b> All objects live a double life as a Python object. 03244 * - <b>Callbacks:</b> When objects are created or deleted, 03245 * interested classes or objects can get a callback notification. 03246 * - <b>Serialization:</b> Objects need to be persisted and later restored. 03247 * Subclasses that don't need to be persisted can skip the implementation 03248 * of the writeElement method.<br> 03249 * Instances can be marked as hidden, which means that they are not 03250 * serialized at all. 03251 */ 03252 class Object : public PythonExtensionBase 03253 { 03254 public: 03255 /** Constructor. */ 03256 explicit Object() {} 03257 03258 /** Destructor. */ 03259 virtual ~Object() {} 03260 03261 /** Called while writing the model into an XML-file. 03262 * The user class should write itself out, using the IOutStream 03263 * members for its "simple" members and calling writeElement 03264 * recursively for any contained objects. 03265 * Not all classes are expected to implement this method. In instances 03266 * of such a class can be created but can't be persisted. 03267 * E.g. Command 03268 */ 03269 virtual void writeElement(XMLOutput *, const Keyword &, mode=DEFAULT) const 03270 {throw LogicException("Class can't be persisted");} 03271 03272 /** Called while restoring the model from an XML-file.<br> 03273 * This is called for each element within the "this" element, 03274 * for which the "this" element is immediate parent.<br> 03275 * It is called when the open element tag is encountered. 03276 */ 03277 virtual void beginElement(XMLInput&, const Attribute&) {} 03278 03279 /** Called while restoring the model from an XML-file.<br> 03280 * This is called when the corresponding close element tag 03281 * is encountered, and the Data() member of pElement is valid. 03282 */ 03283 virtual void endElement(XMLInput&, const Attribute&, const DataElement&) = 0; 03284 03285 /** Mark the object as hidden or not. Hidden objects are not exported 03286 * and are used only as dummy constructs. */ 03287 virtual void setHidden(bool b) {} 03288 03289 /** Returns whether an entity is real or dummy. */ 03290 virtual bool getHidden() const {return false;} 03291 03292 /** This returns the type information on the object, a bit similar to 03293 * the standard type_info information. */ 03294 virtual const MetaClass& getType() const = 0; 03295 03296 /** Return the memory size of the object in bytes. */ 03297 virtual size_t getSize() const = 0; 03298 03299 /** This template function can generate a factory method for objects that 03300 * can be constructed with their default constructor. */ 03301 template <class T> 03302 static Object* createDefault() 03303 { 03304 return new T(); 03305 } 03306 03307 /** This template function can generate a factory method for objects that 03308 * need a string argument in their constructor. */ 03309 template <class T> 03310 static Object* createString(const string& n) 03311 { 03312 return new T(n); 03313 } 03314 03315 /** Template function that generates a factory method callable 03316 * from Python. */ 03317 template<class T> 03318 static PyObject* create 03319 (PyTypeObject* pytype, PyObject* args, PyObject* kwds) 03320 { 03321 try 03322 { 03323 // Find or create the C++ object 03324 PythonAttributeList atts(kwds); 03325 Object* x = T::reader(T::metadata, atts); 03326 03327 // Object was deleted 03328 if (!x) 03329 { 03330 Py_INCREF(Py_None); 03331 return Py_None; 03332 } 03333 03334 // Iterate over extra keywords, and set attributes. @todo move this responsability to the readers... 03335 PyObject *key, *value; 03336 Py_ssize_t pos = 0; 03337 while (PyDict_Next(kwds, &pos, &key, &value)) 03338 { 03339 PythonObject field(value); 03340 Attribute attr(PyString_AsString(key)); 03341 if (!attr.isA(Tags::tag_name) && !attr.isA(Tags::tag_type) && !attr.isA(Tags::tag_action)) 03342 { 03343 int result = x->setattro(attr, field); 03344 if (result && !PyErr_Occurred()) 03345 PyErr_Format(PyExc_AttributeError, 03346 "attribute '%s' on '%s' can't be updated", 03347 PyString_AsString(key), x->ob_type->tp_name); 03348 } 03349 }; 03350 Py_INCREF(x); 03351 return x; 03352 } 03353 catch (...) 03354 { 03355 PythonType::evalException(); 03356 return NULL; 03357 } 03358 } 03359 03360 /** Return an XML representation of the object.<br> 03361 * If a file object is passed as argument, the representation is directly 03362 * written to it.<br> 03363 * If no argument is given the representation is returned as a string. 03364 */ 03365 static DECLARE_EXPORT PyObject* toXML(PyObject*, PyObject*); 03366 }; 03367 03368 03369 // 03370 // UTILITY CLASSES FOR MULTITHREADING 03371 // 03372 03373 03374 /** @brief This class is a wrapper around platform specific mutex functions. */ 03375 class Mutex: public NonCopyable 03376 { 03377 public: 03378 #ifndef MT 03379 // No threading support, empty class 03380 Mutex() {} 03381 ~Mutex() {} 03382 void lock() {} 03383 void unlock() {} 03384 #elif defined(HAVE_PTHREAD_H) 03385 // Pthreads 03386 Mutex() {pthread_mutex_init(&mtx, 0);} 03387 ~Mutex() {pthread_mutex_destroy(&mtx);} 03388 void lock() {pthread_mutex_lock(&mtx);} 03389 void unlock() {pthread_mutex_unlock(&mtx);} 03390 private: 03391 pthread_mutex_t mtx; 03392 #else 03393 // Windows critical section 03394 Mutex() {InitializeCriticalSection(&critsec);} 03395 ~Mutex() {DeleteCriticalSection(&critsec);} 03396 void lock() {EnterCriticalSection(&critsec);} 03397 void unlock() {LeaveCriticalSection(&critsec);} 03398 private: 03399 CRITICAL_SECTION critsec; 03400 #endif 03401 }; 03402 03403 03404 /** @brief This is a convenience class that makes it easy (and 03405 * exception-safe) to lock a mutex in a scope. 03406 */ 03407 class ScopeMutexLock: public NonCopyable 03408 { 03409 protected: 03410 Mutex& mtx; 03411 public: 03412 ScopeMutexLock(Mutex& imtx): mtx(imtx) {mtx.lock ();} 03413 ~ScopeMutexLock() {mtx.unlock();} 03414 }; 03415 03416 03417 /** @brief This class supports parallel execution of a number of functions. 03418 * 03419 * Currently Pthreads and Windows threads are supported as the implementation 03420 * of the multithreading. 03421 */ 03422 class ThreadGroup : public NonCopyable 03423 { 03424 public: 03425 /** Prototype of the thread function. */ 03426 typedef void (*callable)(void*); 03427 03428 /** Constructor which defaults to have as many worker threads as there are 03429 * cores on the machine. 03430 */ 03431 ThreadGroup() : countCallables(0) 03432 { 03433 maxParallel = Environment::getProcessorCores(); 03434 }; 03435 03436 /** Constructor with a predefined number of worker threads. */ 03437 ThreadGroup(int i) : countCallables(0) 03438 { 03439 setMaxParallel(i); 03440 }; 03441 03442 /** Add a new function to be called and its argument. */ 03443 void add(callable func, void* args) 03444 { 03445 callables.push( make_pair(func,args) ); 03446 ++countCallables; 03447 } 03448 03449 /** Execute all functions and wait for them to finish. */ 03450 DECLARE_EXPORT void execute(); 03451 03452 /** Returns the number of parallel workers that is activated.<br> 03453 * By default we activate as many worker threads as there are cores on 03454 * the machine. 03455 */ 03456 int getMaxParallel() const {return maxParallel;} 03457 03458 /** Updates the number of parallel workers that is activated. */ 03459 void setMaxParallel(int b) 03460 { 03461 if (b<1) 03462 throw DataException("Invalid number of parallel execution threads"); 03463 #ifndef MT 03464 maxParallel = (b>1 ? 1 : b); 03465 #else 03466 maxParallel = b; 03467 #endif 03468 } 03469 03470 private: 03471 typedef pair<callable,void*> callableWithArgument; 03472 03473 /** Mutex to protect the curCommand data field during multi-threaded 03474 * execution. 03475 * @see selectCommand 03476 */ 03477 Mutex lock; 03478 03479 /** Specifies the maximum number of commands in the list that can be 03480 * executed in parallel. 03481 * The default value is 1, i.e. sequential execution.<br> 03482 * The value of this field is NOT inherited from parent command lists.<br> 03483 * Note that the maximum applies to this command list only, and it isn't 03484 * a system-wide limit on the creation of threads. 03485 */ 03486 int maxParallel; 03487 03488 /** Stack with all registered functions and their invocation arguments. */ 03489 stack<callableWithArgument> callables; 03490 03491 /** Count registered callables. */ 03492 unsigned int countCallables; 03493 03494 /** This functions runs a single command execution thread. It is used as 03495 * a holder for the main routines of a trheaded routine. 03496 */ 03497 #if defined(HAVE_PTHREAD_H) || !defined(MT) 03498 static void* wrapper(void *arg); 03499 #else 03500 static unsigned __stdcall wrapper(void *); 03501 #endif 03502 03503 /** This method selects the next function to be executed. 03504 * @see wrapper 03505 */ 03506 DECLARE_EXPORT callableWithArgument selectNextCallable(); 03507 }; 03508 03509 03510 // 03511 // RED-BLACK TREE CLASS 03512 // 03513 03514 /** @brief This class implements a binary tree data structure. It is used as a 03515 * container for entities keyed by their name. 03516 * 03517 * Technically, the data structure can be described as a red-black tree 03518 * with intrusive tree nodes. 03519 * @see HasName 03520 */ 03521 class Tree : public NonCopyable 03522 { 03523 public: 03524 /** The algorithm assigns a color to each node in the tree. The color is 03525 * used to keep the tree balanced.<br> 03526 * A node with color 'none' is a node that hasn't been inserted yet in 03527 * the tree. 03528 */ 03529 enum NodeColor {red, black, none }; 03530 03531 /** @brief This class represents a node in the tree. 03532 * 03533 * Elements which we want to represent in the tree will need to inherit 03534 * from this class, since this tree container is intrusive. 03535 */ 03536 class TreeNode 03537 { 03538 friend class Tree; 03539 03540 public: 03541 /** Destructor. */ 03542 virtual ~TreeNode() {} 03543 03544 /** Returns the name of this node. This name is used to sort the 03545 * nodes. */ 03546 const string& getName() const {return nm;} 03547 03548 /** Comparison operator. */ 03549 bool operator < (const TreeNode& o) {return nm < o.nm;} 03550 03551 /** Constructor. */ 03552 TreeNode(const string& n) : nm(n), color(none) 03553 { 03554 if (n.empty()) 03555 throw DataException("Can't create entity without name"); 03556 } 03557 03558 /** Return a pointer to the node following this one. */ 03559 TreeNode* increment() const 03560 { 03561 TreeNode *node = const_cast<TreeNode*>(this); 03562 if (node->right != NULL) 03563 { 03564 node = node->right; 03565 while (node->left != NULL) node = node->left; 03566 } 03567 else 03568 { 03569 TreeNode* y = node->parent; 03570 while (node == y->right) 03571 { 03572 node = y; 03573 y = y->parent; 03574 } 03575 if (node->right != y) node = y; 03576 } 03577 return node; 03578 } 03579 03580 /** Return a pointer to the node preceding this one. */ 03581 TreeNode* decrement() const 03582 { 03583 TreeNode *node = const_cast<TreeNode*>(this); 03584 if (node->color == red && node->parent->parent == node) 03585 node = node->right; 03586 else if (node->left != NULL) 03587 { 03588 TreeNode* y = node->left; 03589 while (y->right != NULL) y = y->right; 03590 node = y; 03591 } 03592 else 03593 { 03594 TreeNode* y = node->parent; 03595 while (node == y->left) 03596 { 03597 node = y; 03598 y = y->parent; 03599 } 03600 node = y; 03601 } 03602 return node; 03603 } 03604 03605 private: 03606 /** Constructor. */ 03607 TreeNode() {} 03608 03609 /** Name. */ 03610 string nm; 03611 03612 /** Color of the node. This is used to keep the tree balanced. */ 03613 NodeColor color; 03614 03615 /** Pointer to the parent node. */ 03616 TreeNode* parent; 03617 03618 /** Pointer to the left child node. */ 03619 TreeNode* left; 03620 03621 /** Pointer to the right child node. */ 03622 TreeNode* right; 03623 }; 03624 03625 /** Default constructor. */ 03626 Tree(bool b = false) : count(0), clearOnDestruct(b) 03627 { 03628 // Color is used to distinguish header from root, in iterator.operator++ 03629 header.color = red; 03630 header.parent = NULL; 03631 header.left = &header; 03632 header.right = &header; 03633 } 03634 03635 /** Destructor.<br> 03636 * By default, the objects in the tree are not deleted when the tree 03637 * is deleted. This is done for performance reasons: the program can shut 03638 * down faster. 03639 */ 03640 ~Tree() {if(clearOnDestruct) clear();} 03641 03642 /** Returns an iterator to the start of the list.<br> 03643 * The user will need to take care of properly acquiring a read lock on 03644 * on the tree object. 03645 */ 03646 TreeNode* begin() const {return const_cast<TreeNode*>(header.left);} 03647 03648 /** Returns an iterator pointing beyond the last element in the list.<br> 03649 * The user will need to take care of properly acquiring a read lock on 03650 * on the tree object. 03651 */ 03652 TreeNode* end() const {return const_cast<TreeNode*>(&header);} 03653 03654 /** Returns true if the list is empty.<br> 03655 * Its complexity is O(1). */ 03656 bool empty() const 03657 { 03658 ScopeMutexLock l(const_cast<Mutex&>(treeaccess)); 03659 return header.parent == NULL; 03660 } 03661 03662 /** Renames an existing node, and adjusts its position in the tree. */ 03663 void rename(TreeNode* obj, string newname) 03664 { 03665 bool found; 03666 findLowerBound(newname, &found); 03667 if (found) 03668 throw DataException("Can't rename '" + obj->nm + "' to '" 03669 + newname + "': name already in use"); 03670 erase(obj); 03671 // @todo: there is a small risk for multithreading trouble when the tree is unlocked between the delete and re-insert 03672 obj->nm = newname; 03673 insert(obj); 03674 }; 03675 03676 /** This method returns the number of nodes inserted in this tree.<br> 03677 * Its complexity is O(1), so it can be called on large trees without any 03678 * performance impact. 03679 */ 03680 size_t size() const 03681 { 03682 ScopeMutexLock l(const_cast<Mutex&>(treeaccess)); 03683 return count; 03684 } 03685 03686 /** Verifies the integrity of the tree and returns true if everything 03687 * is correct.<br> 03688 * The tree should be locked before calling this function. 03689 */ 03690 DECLARE_EXPORT void verify() const; 03691 03692 /** Remove all elements from the tree. */ 03693 DECLARE_EXPORT void clear(); 03694 03695 /** Remove a node from the tree. */ 03696 DECLARE_EXPORT void erase(TreeNode* x); 03697 03698 /** Search for an element in the tree.<br> 03699 * Profiling shows this function has a significant impact on the CPU 03700 * time (mainly because of the string comparisons), and has been 03701 * optimized as much as possible. 03702 */ 03703 TreeNode* find(const string& k) const 03704 { 03705 ScopeMutexLock l(const_cast<Mutex&>(treeaccess)); 03706 int comp; 03707 for (TreeNode* x = header.parent; x; x = comp<0 ? x->left : x->right) 03708 { 03709 comp = k.compare(x->nm); 03710 if (!comp) return x; 03711 } 03712 TreeNode* result = end(); 03713 return result; 03714 } 03715 03716 /** Find the element with this given key or the element 03717 * immediately preceding it.<br> 03718 * The second argument is a boolean that is set to true when the 03719 * element is found in the list. 03720 */ 03721 TreeNode* findLowerBound(const string& k, bool* f) const 03722 { 03723 ScopeMutexLock l(const_cast<Mutex&>(treeaccess)); 03724 TreeNode* lower = end(); 03725 for (TreeNode* x = header.parent; x;) 03726 { 03727 int comp = k.compare(x->nm); 03728 if (!comp) 03729 { 03730 // Found 03731 if (f) *f = true; 03732 return x; 03733 } 03734 if (comp<0) x = x->left; 03735 else lower = x, x = x->right; 03736 } 03737 if (f) *f = false; 03738 return lower; 03739 } 03740 03741 /** Insert a new node in the tree. */ 03742 TreeNode* insert(TreeNode* v) {return insert(v, NULL);} 03743 03744 /** Insert a new node in the tree. The second argument is a hint on 03745 * the proper location in the tree.<br> 03746 * Profiling shows this function has a significant impact on the cpu 03747 * time (mainly because of the string comparisons), and has been 03748 * optimized as much as possible. 03749 */ 03750 DECLARE_EXPORT TreeNode* insert(TreeNode* v, TreeNode* hint); 03751 03752 private: 03753 /** Restructure the tree such that the depth of the branches remains 03754 * properly balanced. This method is called during insertion. */ 03755 inline void rebalance(TreeNode* x); 03756 03757 /** Rebalancing operation used during the rebalancing. */ 03758 inline void rotateLeft(TreeNode* x); 03759 03760 /** Rebalancing operation used during the rebalancing. */ 03761 inline void rotateRight(TreeNode* x); 03762 03763 /** Method used internally by the verify() method. */ 03764 unsigned int countBlackNodes(TreeNode* node) const 03765 { 03766 unsigned int sum = 0; 03767 for ( ; node != header.parent; node=node->parent) 03768 if (node->color == black) ++sum; 03769 return sum; 03770 } 03771 03772 TreeNode* minimum(TreeNode* x) const 03773 { 03774 while (x->left) x = x->left; 03775 return x; 03776 } 03777 03778 TreeNode* maximum(TreeNode* x) const 03779 { 03780 while (x->right) x = x->right; 03781 return x; 03782 } 03783 03784 /** This node stores the following data: 03785 * - parent: root of the tree. 03786 * - left: leftmost element in the tree. 03787 * - right: rightmost element in the tree. 03788 * - this node itself is used as an element beyond the end of the list. 03789 */ 03790 TreeNode header; 03791 03792 /** Stores the number of elements in the tree. */ 03793 size_t count; 03794 03795 /** Controls concurrent access to the tree from different trheads.<br> 03796 * Every function reading or updating the tree should keep this mutex 03797 * locked during the operation. 03798 */ 03799 Mutex treeaccess; 03800 03801 /** Controls whether the destructor needs to be clear all objects in the 03802 * tree in its destructor.<br> 03803 * The default is to skip this cleanup! This is fine when you are dealing 03804 * with a static tree that lives throughout your program.<br> 03805 * When you create a tree with a shorter lifespan, you'll need to pass 03806 * the constructor 'true' as argument in order to avoid memory leaks. 03807 */ 03808 bool clearOnDestruct; 03809 }; 03810 03811 03812 // 03813 // UTILITY CLASS "COMMAND": for executing & undoing actions 03814 // 03815 03816 /** @brief Abstract base class for all commands. 03817 * 03818 * Command objects are designed for algorithms that need to keep track of 03819 * their decision, efficiently undo them and redo them. 03820 * 03821 * The key methods are: 03822 * - The constructor or other methods on the concrete subclasses 03823 * implement the state change. 03824 * - commit(): 03825 * Makes the change permanently. 03826 * Undoing the change is no longer possible after calling this method. 03827 * - rollback(): 03828 * Reverts the change permanently. 03829 * Redoing the change is no longer possible after calling this method. 03830 * - undo(): 03831 * Temporarily reverts the change. 03832 * Redoing the change is still possible. 03833 * - redo(): 03834 * Reactivates the change that was previously undone. 03835 */ 03836 class Command 03837 { 03838 friend class CommandList; 03839 friend class CommandManager; 03840 friend class frepple::CommandMoveOperationPlan; 03841 public: 03842 /** Default constructor. The creation of a command should NOT execute the 03843 * command yet. The execute() method needs to be called explicitly to 03844 * do so. 03845 */ 03846 Command() : owner(NULL), next(NULL), prev(NULL) {}; 03847 03848 /** This method makes the change permanent.<br> 03849 * A couple of notes on how this method should be implemented by the 03850 * subclasses: 03851 * - Calling the method multiple times is harmless. Only the first 03852 * call is expected to do something. 03853 */ 03854 virtual void commit() {}; 03855 03856 /** This method permanently undoes the change.<br> 03857 * A couple of notes on how this method should be implemented by the 03858 * subclasses: 03859 * - Calling the rollback() method multiple times is harmless. Only 03860 * the first call is expected to do something. 03861 */ 03862 virtual void rollback() {}; 03863 03864 /** This method temporarily undoes the change. The concrete subclasses 03865 * most maintain information that enables redoing the changes 03866 * efficiently.<br> 03867 * A couple of notes on how this method should be implemented by the 03868 * subclasses: 03869 * - Calling the method multiple times is harmless and results in the 03870 * same state change as calling it only once. 03871 */ 03872 virtual void undo() {}; 03873 03874 /** This method reproduces a previously undone change.<br> 03875 * A couple of notes on how this method should be implemented by the 03876 * subclasses: 03877 * - Calling the method multiple times is harmless and results in the 03878 * same state change as calling it only once. 03879 */ 03880 virtual void redo() {}; 03881 03882 /** Destructor. */ 03883 virtual ~Command() {}; 03884 03885 private: 03886 /** Points to the commandlist which owns this command. The default value 03887 * is NULL, meaning there is no owner. */ 03888 Command *owner; 03889 03890 /** Points to the next command in the owner command list.<br> 03891 * The commands are chained in a double linked list data structure. */ 03892 Command *next; 03893 03894 /** Points to the previous command in the owner command list.<br> 03895 * The commands are chained in a double linked list data structure. */ 03896 Command *prev; 03897 }; 03898 03899 03900 /** @brief A container command to group a series of commands together. 03901 * 03902 * This class implements the "composite" design pattern in order to get an 03903 * efficient and intuitive hierarchical grouping of commands. 03904 * @todo handle exceptions during commit, rollback, undo, redo 03905 */ 03906 class CommandList : public Command 03907 { 03908 private: 03909 /** Points to the first command in the list.<br> 03910 * Following commands can be found by following the next pointers 03911 * on the commands.<br> 03912 * The commands are this chained in a double linked list data structure. 03913 */ 03914 Command* firstCommand; 03915 03916 /** Points to the last command in the list. */ 03917 Command* lastCommand; 03918 public: 03919 class iterator 03920 { 03921 public: 03922 /** Constructor. */ 03923 iterator(Command* x) : cur(x) {} 03924 03925 /** Copy constructor. */ 03926 iterator(const iterator& it) {cur = it.cur;} 03927 03928 /** Return the content of the current node. */ 03929 Command& operator*() const {return *cur;} 03930 03931 /** Return the content of the current node. */ 03932 Command* operator->() const {return cur;} 03933 03934 /** Pre-increment operator which moves the pointer to the next 03935 * element. */ 03936 iterator& operator++() 03937 { 03938 cur = cur->next; 03939 return *this; 03940 } 03941 03942 /** Post-increment operator which moves the pointer to the next 03943 * element. */ 03944 iterator operator++(int) 03945 { 03946 iterator tmp = *this; 03947 cur = cur->next; 03948 return tmp; 03949 } 03950 03951 /** Comparison operator. */ 03952 bool operator==(const iterator& y) const {return cur==y.cur;} 03953 03954 /** Inequality operator. */ 03955 bool operator!=(const iterator& y) const {return cur!=y.cur;} 03956 03957 private: 03958 Command* cur; 03959 }; 03960 03961 /** Returns an iterator over all commands in the list. */ 03962 iterator begin() const {return iterator(firstCommand);} 03963 03964 /** Returns an iterator beyond the last command. */ 03965 iterator end() const {return iterator(NULL);} 03966 03967 /** Append an additional command to the end of the list. */ 03968 DECLARE_EXPORT void add(Command* c); 03969 03970 /** Undoes all actions on the list.<br> 03971 * At the end it also clears the list of actions. 03972 */ 03973 virtual DECLARE_EXPORT void rollback(); 03974 03975 /** Commits all actions on its list.<br> 03976 * At the end it also clears the list of actions. 03977 */ 03978 virtual DECLARE_EXPORT void commit(); 03979 03980 /** Undoes all actions on its list.<br> 03981 * The list of actions is left intact, so the changes can still be redone. 03982 */ 03983 virtual DECLARE_EXPORT void undo(); 03984 03985 /** Redoes all actions on its list.<br> 03986 * The list of actions is left intact, so the changes can still be undone. 03987 */ 03988 DECLARE_EXPORT void redo(); 03989 03990 /** Returns true if no commands have been added yet to the list. */ 03991 bool empty() const {return firstCommand==NULL;} 03992 03993 /** Default constructor. */ 03994 explicit CommandList() : firstCommand(NULL), lastCommand(NULL) {} 03995 03996 /** Destructor.<br> 03997 * A commandlist should only be deleted when all of its commands 03998 * have been committed or undone. If this is not the case a warning 03999 * will be printed. 04000 */ 04001 virtual DECLARE_EXPORT ~CommandList(); 04002 }; 04003 04004 04005 /** @brief This class allows management of tasks with supporting commiting them, 04006 * rolling them back, and setting bookmarks which can be undone and redone. 04007 */ 04008 class CommandManager 04009 { 04010 public: 04011 /** A bookmark that keeps track of commands that can be undone and redone. */ 04012 class Bookmark : public CommandList 04013 { 04014 friend class CommandManager; 04015 private: 04016 bool active; 04017 Bookmark* nextBookmark; 04018 Bookmark* prevBookmark; 04019 Bookmark* parent; 04020 Bookmark(Bookmark* p=NULL) : active(true), 04021 nextBookmark(NULL), prevBookmark(NULL), parent(p) {} 04022 public: 04023 /** Returns true if the bookmark commands are active. */ 04024 bool isActive() const {return active;} 04025 04026 /** Returns true if the bookmark is a child, grand-child or 04027 * grand-grand-child of the argument bookmark. 04028 */ 04029 bool isChildOf(const Bookmark* b) const 04030 { 04031 for (const Bookmark* p = this; p; p = p->parent) 04032 if (p == b) return true; 04033 return false; 04034 } 04035 }; 04036 04037 /** An STL-like iterator to move over all bookmarks in forward order. */ 04038 class iterator 04039 { 04040 public: 04041 /** Constructor. */ 04042 iterator(Bookmark* x) : cur(x) {} 04043 04044 /** Copy constructor. */ 04045 iterator(const iterator& it) {cur = it.cur;} 04046 04047 /** Return the content of the current node. */ 04048 Bookmark& operator*() const {return *cur;} 04049 04050 /** Return the content of the current node. */ 04051 Bookmark* operator->() const {return cur;} 04052 04053 /** Pre-increment operator which moves the pointer to the next 04054 * element. */ 04055 iterator& operator++() 04056 { 04057 cur = cur->nextBookmark; 04058 return *this; 04059 } 04060 04061 /** Post-increment operator which moves the pointer to the next 04062 * element. */ 04063 iterator operator++(int) 04064 { 04065 iterator tmp = *this; 04066 cur = cur->nextBookmark; 04067 return tmp; 04068 } 04069 04070 /** Comparison operator. */ 04071 bool operator==(const iterator& y) const {return cur==y.cur;} 04072 04073 /** Inequality operator. */ 04074 bool operator!=(const iterator& y) const {return cur!=y.cur;} 04075 04076 private: 04077 Bookmark* cur; 04078 }; 04079 04080 /** An STL-like iterator to move over all bookmarks in reverse order. */ 04081 class reverse_iterator 04082 { 04083 public: 04084 /** Constructor. */ 04085 reverse_iterator(Bookmark* x) : cur(x) {} 04086 04087 /** Copy constructor. */ 04088 reverse_iterator(const reverse_iterator& it) {cur = it.cur;} 04089 04090 /** Return the content of the current node. */ 04091 Bookmark& operator*() const {return *cur;} 04092 04093 /** Return the content of the current node. */ 04094 Bookmark* operator->() const {return cur;} 04095 04096 /** Pre-increment operator which moves the pointer to the next 04097 * element. */ 04098 reverse_iterator& operator++() 04099 { 04100 cur = cur->prevBookmark; 04101 return *this; 04102 } 04103 04104 /** Post-increment operator which moves the pointer to the next 04105 * element. */ 04106 reverse_iterator operator++(int) 04107 { 04108 reverse_iterator tmp = *this; 04109 cur = cur->prevBookmark; 04110 return tmp; 04111 } 04112 04113 /** Comparison operator. */ 04114 bool operator==(const reverse_iterator& y) const {return cur==y.cur;} 04115 04116 /** Inequality operator. */ 04117 bool operator!=(const reverse_iterator& y) const {return cur!=y.cur;} 04118 04119 private: 04120 Bookmark* cur; 04121 }; 04122 04123 private: 04124 /** Head of a list of bookmarks.<br> 04125 * A command manager has always at least this default bookmark. 04126 */ 04127 Bookmark firstBookmark; 04128 04129 /** Tail of a list of bookmarks. */ 04130 Bookmark* lastBookmark; 04131 04132 /** Current bookmarks.<br> 04133 * If commands are added to the manager, this is the bookmark where 04134 * they'll be appended to. 04135 */ 04136 Bookmark* currentBookmark; 04137 04138 public: 04139 /** Constructor. */ 04140 CommandManager() 04141 { 04142 lastBookmark = &firstBookmark; 04143 currentBookmark = &firstBookmark; 04144 } 04145 04146 /** Destructor. */ 04147 ~CommandManager() 04148 { 04149 for (Bookmark* i = lastBookmark; i && i != &firstBookmark; ) 04150 { 04151 Bookmark* tmp = i; 04152 i = i->prevBookmark; 04153 delete tmp; 04154 } 04155 } 04156 04157 /** Returns an iterator over all bookmarks in forward direction. */ 04158 iterator begin() {return iterator(&firstBookmark);} 04159 04160 /** Returns an iterator beyond the last bookmark in forward direction. */ 04161 iterator end() {return iterator(NULL);} 04162 04163 /** Returns an iterator over all bookmarks in reverse direction. */ 04164 reverse_iterator rbegin() {return reverse_iterator(lastBookmark);} 04165 04166 /** Returns an iterator beyond the last bookmark in reverse direction. */ 04167 reverse_iterator rend() {return reverse_iterator(NULL);} 04168 04169 /** Add a command to the active bookmark. */ 04170 void add(Command* c) {currentBookmark->add(c);} 04171 04172 /** Create a new bookmark. */ 04173 DECLARE_EXPORT Bookmark* setBookmark(); 04174 04175 /** Undo all commands in a bookmark (and its children).<br> 04176 * It can later be redone.<br> 04177 * The active bookmark in the manager is set to the parent of 04178 * argument bookmark. 04179 */ 04180 DECLARE_EXPORT void undoBookmark(Bookmark*); 04181 04182 /** Redo all commands in a bookmark (and its children).<br> 04183 * It can later still be undone.<br> 04184 * The active bookmark in the manager is set to the argument bookmark. 04185 */ 04186 DECLARE_EXPORT void redoBookmark(Bookmark*); 04187 04188 /** Undo all commands in a bookmark (and its children).<br> 04189 * It can no longer be redone. The bookmark does however still exist. 04190 */ 04191 DECLARE_EXPORT void rollback(Bookmark*); 04192 04193 /** Commit all commands. */ 04194 DECLARE_EXPORT void commit(); 04195 04196 /** Rolling back all commands. */ 04197 DECLARE_EXPORT void rollback(); 04198 }; 04199 04200 04201 // 04202 // INPUT PROCESSING CLASSES 04203 // 04204 04205 04206 /** @brief This class will read in an XML-file and call the appropriate 04207 * handler functions of the Object classes and objects. 04208 * 04209 * This class is implemented based on the Xerces SAX XML parser. 04210 * For debugging purposes a flag is defined at the start of the file 04211 * "xmlparser.cpp". Uncomment the line and recompile to use it. 04212 * 04213 * FrePPLe creates a new parser and loads the XML schema every time 04214 * XML data need to be parsed. When this happens only a few times during a 04215 * run this is good enough.<br> 04216 * However, when the libary has to parse plenty of small XML messages this 04217 * will create a significant overhead. The code would need to be enhanced 04218 * to maintain a pool of parsers and cache their grammars. 04219 */ 04220 class XMLInput : public NonCopyable, private xercesc::DefaultHandler 04221 { 04222 public: 04223 typedef pair<Attribute,XMLElement> datapair; 04224 04225 private: 04226 /** A pointer to an XML parser for processing the input. */ 04227 xercesc::SAX2XMLReader* parser; 04228 04229 /** This type defines the different states the parser can have. */ 04230 enum state 04231 { 04232 /** The parser is sending input to an object handler. */ 04233 READOBJECT, 04234 /** The parser has been instructed to ignore a tag. */ 04235 IGNOREINPUT, 04236 /** The parser is shutting down, and will ignore all further data. */ 04237 SHUTDOWN, 04238 /** This state is only used when the parser starts processing its first 04239 * tag. */ 04240 INIT 04241 }; 04242 04243 /** This variable defines the maximum depth of the object creation stack. 04244 * This maximum is intended to protect us from malicious malformed 04245 * xml-documents, and also for allocating efficient data structures for 04246 * the parser. 04247 */ 04248 const unsigned short maxdepth; 04249 04250 /** Stack of states. */ 04251 stack <state> states; 04252 04253 /** Previous object in stack. */ 04254 Object* prev; 04255 04256 /** Stack of pairs. The pairs contain: 04257 * - A pointer to an event handler object. The beginElement and 04258 * endElement methods of this object will be called. 04259 * - A user definable pointer. The purpose of this pointer is to store 04260 * status information between calls to the handler. 04261 */ 04262 vector< pair<Object*,void*> > m_EHStack; 04263 04264 /** Stack of elements.<br> 04265 * The expression m_EStack[numElements+1] returns the current element.<br> 04266 * The expression m_EStack[numElements] returns the parent element. 04267 * @see numElements 04268 */ 04269 vector<datapair> m_EStack; 04270 04271 /** A variable to keep track of the size of the element stack. It is used 04272 * together with the variable m_EStack. 04273 * @see m_EStack 04274 */ 04275 short numElements; 04276 04277 /** This field counts how deep we are in a nested series of ignored input. 04278 * It is represented as a counter since the ignored element could contain 04279 * itself. 04280 */ 04281 unsigned short ignore; 04282 04283 /** Hash value of the current element. */ 04284 stack<hashtype> endingHashes; 04285 04286 /** This variable is normally false. It is switched to true only a) in 04287 * the method endElement() of Object objects and b) when an object 04288 * is processing its closing tag. 04289 */ 04290 bool objectEnded; 04291 04292 /** This field controls whether we continue processing after data errors 04293 * or whether we abort processing the remaining XML data.<br> 04294 * Selecting the right mode is important: 04295 * - Setting the flag to false is appropriate for processing large 04296 * amounts of a bulk-load operation. In this mode a single, potentially 04297 * minor, data problem won't abort the complete process. 04298 * - Setting the flag to true is most appropriate to process small and 04299 * frequent messages from client applications. In this mode client 04300 * applications are notified about data problems. 04301 * - The default setting is true, in order to provide a maximum level of 04302 * security for the application. 04303 */ 04304 bool abortOnDataException; 04305 04306 /** This is a pointer to the attributes. 04307 * See the xerces API documentation for further information on the usage 04308 * of the attribute list. 04309 */ 04310 XMLAttributeList attributes; 04311 04312 /** Handler called when a new element tag is encountered. 04313 * It pushes a new element on the stack and calls the current handler. 04314 */ 04315 void startElement (const XMLCh* const, const XMLCh* const, 04316 const XMLCh* const, const xercesc::Attributes&); 04317 04318 /** Handler called when closing element tag is encountered. 04319 * If this is the closing tag for the current event handler, pop it 04320 * off the handler stack. If this empties the stack, shut down parser. 04321 * Otherwise, just feed the element with the already completed 04322 * data section to the current handler, then pop it off the element 04323 * stack. 04324 */ 04325 void endElement 04326 (const XMLCh* const, const XMLCh* const, const XMLCh* const); 04327 04328 /** Handler called when character data are read in. 04329 * The data string is add it to the current element data. 04330 */ 04331 #if XERCES_VERSION_MAJOR==2 04332 void characters(const XMLCh *const, const unsigned int); 04333 #else 04334 void characters(const XMLCh *const, const XMLSize_t); 04335 #endif 04336 04337 /** Handler called by Xerces in fatal error conditions. It throws an 04338 * exception to abort the parsing procedure. */ 04339 void fatalError (const xercesc::SAXParseException& e) {throw e;} 04340 04341 /** Handler called by Xercess when reading a processing instruction. The 04342 * handler looks up the target in the repository and will call the 04343 * registered XMLinstruction. 04344 * @see XMLinstruction 04345 */ 04346 void processingInstruction (const XMLCh *const, const XMLCh *const); 04347 04348 /** Handler called by Xerces in error conditions. It throws an exception 04349 * to abort the parsing procedure. */ 04350 void error (const xercesc::SAXParseException& e) {throw e;} 04351 04352 /** Handler called by Xerces for warnings. */ 04353 void warning (const xercesc::SAXParseException&); 04354 04355 /** This method cleans up the parser state to get it ready for processing 04356 * a new document. */ 04357 void reset(); 04358 04359 /** Return a pointer to the current object being read in. */ 04360 inline Object* getCurrentObject() const {return m_EHStack[m_EHStack.size()-1].first;} 04361 04362 public: 04363 /** Constructor. 04364 * @param maxNestedElmnts Defines the maximum depth of elements an XML 04365 * document is allowed to have. The default is 20. 04366 */ 04367 XMLInput(unsigned short maxNestedElmnts = 20) 04368 : parser(NULL), maxdepth(maxNestedElmnts), m_EStack(maxNestedElmnts+2), 04369 numElements(-1), ignore(0), objectEnded(false), 04370 abortOnDataException(true), attributes(NULL) {} 04371 04372 /** Destructor. */ 04373 virtual ~XMLInput() {reset();} 04374 04375 /** Return a pointer to an array of character pointer which point 04376 * to the attributes. See the xerces documentation if this description 04377 * doesn't satisfy you... 04378 */ 04379 const AttributeList& getAttributes() const {return attributes;} 04380 04381 /** Redirect event stream into a new Object.<br> 04382 * It is also possible to pass a NULL pointer to the function. In 04383 * that situation, we simple ignore the content of that element.<br> 04384 * Important: The user is reponsible of making sure the argument 04385 * object has a proper write-lock. The release of that lock is handled 04386 * by the parser. 04387 */ 04388 DECLARE_EXPORT void readto(Object*); 04389 04390 /** Abort the parsing. 04391 * The actual shutdown cannot be called inside a SAX handler function, 04392 * so actual shutdown is deferred until the next iteration of the feed 04393 * loop. 04394 */ 04395 void shutdown(); 04396 04397 /** Ignore an element. */ 04398 void IgnoreElement() {readto(NULL);} 04399 04400 /** Returns true if the current object is finishing with the current 04401 * tag. This method should only be used in the endElement() method. */ 04402 bool isObjectEnd() {return objectEnded;} 04403 04404 /** Invalidates the current object.<br> 04405 * This method is useful when, for instance, the object being parsed 04406 * is being deleted. 04407 */ 04408 void invalidateCurrentObject() 04409 { 04410 if (!m_EHStack.empty()) 04411 m_EHStack[m_EHStack.size()-1].first = NULL; 04412 } 04413 04414 /** Return a pointer to the previous object being read in.<br> 04415 * In a typical use the returned pointer will require a dynamic_cast 04416 * to a subclass type.<br> 04417 * The typical usage is as follows: 04418 * <pre> 04419 * Operation *o = dynamic_cast<Operation*>(pIn.getPreviousObject()); 04420 * if (o) doSomeThing(o); 04421 * else throw LogicException("Incorrect object type"); 04422 * </pre> 04423 */ 04424 Object* getPreviousObject() const {return prev;} 04425 04426 /** Clears the previously read object. */ 04427 Object* getParentObject() const 04428 { 04429 int x = m_EHStack.size(); 04430 return x>1 ? m_EHStack[x-2].first : NULL; 04431 } 04432 04433 /** Returns a reference to the parent element. */ 04434 const datapair& getParentElement() const 04435 {return m_EStack[numElements>0 ? numElements : 0];} 04436 04437 /** Returns a reference to the current element. */ 04438 const datapair& getCurrentElement() const 04439 {return m_EStack[numElements>-1 ? numElements+1 : 0];} 04440 04441 /** This is the core parsing function, which triggers the XML parser to 04442 * start processing the input. It is normally called from the method 04443 * parse(Object*) once a proper stream has been created. 04444 * @see parse(Object*) 04445 */ 04446 void parse(xercesc::InputSource&, Object*, bool=false); 04447 04448 /** Updates the user definable pointer. This pointer is used to store 04449 * status information between handler calls. */ 04450 void setUserArea(void* v) 04451 {if (!m_EHStack.empty()) m_EHStack[m_EHStack.size()-1].second = v;} 04452 04453 /** Returns the user definable pointer. */ 04454 void* getUserArea() const 04455 {return m_EHStack.empty() ? NULL : m_EHStack[m_EHStack.size()-1].second;} 04456 04457 /** Updates whether we ignore data exceptions or whether we abort the 04458 * processing of the XML data stream. */ 04459 void setAbortOnDataError(bool i) {abortOnDataException = i;} 04460 04461 /** Returns the behavior of the parser in case of data errors.<br> 04462 * When true is returned, the processing of the XML stream continues 04463 * after a DataException. Other, more critical, exceptions types will 04464 * still abort the parsing process.<br> 04465 * False indicates that the processing of the XML stream is aborted. 04466 */ 04467 bool getAbortOnDataError() const {return abortOnDataException;} 04468 04469 protected: 04470 /** The real parsing job is delegated to subclasses. 04471 * Subclass can then define the specifics for parsing a flat file, 04472 * a string, a SOAP message, etc... 04473 * @exception RuntimeException Thrown in the following situations: 04474 * - the xml-document is incorrectly formatted 04475 * - the xml-parser librabry can't be initialized 04476 * - no memory can be allocated to the xml-parser 04477 * @exception DataException Thrown when the data can't be processed 04478 * normally by the objects being created or updated. 04479 */ 04480 virtual void parse(Object* s, bool b=false) 04481 { 04482 throw LogicException("Unreachable code reached"); 04483 } 04484 }; 04485 04486 04487 /** @brief This class reads XML data from a string. */ 04488 class XMLInputString : public XMLInput 04489 { 04490 public: 04491 /** Default constructor. */ 04492 XMLInputString(const string& s) : data(s) {}; 04493 04494 /** Parse the specified string. */ 04495 void parse(Object* pRoot, bool v = false) 04496 { 04497 /* The MemBufInputSource expects the number of bytes as second parameter. 04498 * In our case this is the same as the number of characters, but this 04499 * will not apply any more for character sets with multi-byte 04500 * characters. 04501 */ 04502 xercesc::MemBufInputSource a( 04503 reinterpret_cast<const XMLByte*>(data.c_str()), 04504 static_cast<const unsigned int>(data.size()), 04505 "memory data", 04506 false); 04507 XMLInput::parse(a,pRoot,v); 04508 } 04509 04510 private: 04511 /** String containing the data to be parsed. Note that NO local copy of the 04512 * data is made, only a reference is stored. The class relies on the code 04513 * calling the command to correctly create and destroy the string being 04514 * used. 04515 */ 04516 const string data; 04517 }; 04518 04519 04520 /** @brief This class reads XML data from a file system. 04521 * 04522 * The filename argument can be the name of a file or a directory. 04523 * If a directory is passed, all files with the extension ".xml" 04524 * will be read from it. Subdirectories are not recursed. 04525 */ 04526 class XMLInputFile : public XMLInput 04527 { 04528 public: 04529 /** Constructor. The argument passed is the name of a 04530 * file or a directory. */ 04531 XMLInputFile(const string& s) : filename(s) {}; 04532 04533 /** Default constructor. */ 04534 XMLInputFile() {}; 04535 04536 /** Update the name of the file to be processed. */ 04537 void setFileName(const string& s) {filename = s;} 04538 04539 /** Returns the name of the file or directory to process. */ 04540 string getFileName() {return filename;} 04541 04542 /** Parse the specified file. 04543 * When a directory was passed as the argument a failure is 04544 * flagged as soon as a single file returned a failure. All 04545 * files in an directory are processed however, regardless of 04546 * failure with one of the files. 04547 * @exception RuntimeException Generated in the following conditions: 04548 * - no input file or directory has been specified. 04549 * - read access to the input file is not available 04550 * - the program doesn't support reading directories on your platform 04551 */ 04552 void parse(Object*, bool=false); 04553 04554 private: 04555 /** Name of the file to be opened. */ 04556 string filename; 04557 }; 04558 04559 04560 // 04561 // UTILITY CLASSES "HASNAME", "HASHIERARCHY", "HASDESCRIPTION" 04562 // 04563 04564 04565 /** @brief Base class for objects using a string as their primary key. 04566 * 04567 * Instances of this class have the following properties: 04568 * - Have a unique name. 04569 * - A hashtable (keyed on the name) is maintained as a container with 04570 * all active instances. 04571 */ 04572 template <class T> class HasName : public NonCopyable, public Tree::TreeNode, public Object 04573 { 04574 private: 04575 /** Maintains a global list of all created entities. The list is keyed 04576 * by the name. */ 04577 static DECLARE_EXPORT Tree st; 04578 typedef T* type; 04579 04580 public: 04581 /** @brief This class models a STL-like iterator that allows us to 04582 * iterate over the named entities in a simple and safe way. 04583 * 04584 * Objects of this class are created by the begin() and end() functions. 04585 * @todo not thread-safe: needs to lock the tree during iteration 04586 */ 04587 class iterator 04588 { 04589 public: 04590 /** Constructor. */ 04591 iterator(Tree::TreeNode* x) : node(x) {} 04592 04593 /** Copy constructor. */ 04594 iterator(const iterator& it) {node = it.node;} 04595 04596 /** Return the content of the current node. */ 04597 T& operator*() const {return *static_cast<T*>(node);} 04598 04599 /** Return the content of the current node. */ 04600 T* operator->() const {return static_cast<T*>(node);} 04601 04602 /** Pre-increment operator which moves the pointer to the next 04603 * element. */ 04604 iterator& operator++() {node = node->increment(); return *this;} 04605 04606 /** Post-increment operator which moves the pointer to the next 04607 * element. */ 04608 iterator operator++(int) 04609 { 04610 Tree::TreeNode* tmp = node; 04611 node = node->increment(); 04612 return tmp; 04613 } 04614 04615 /** Pre-decrement operator which moves the pointer to the previous 04616 * element. */ 04617 iterator& operator--() {node = node->decrement(); return *this;} 04618 04619 /** Post-decrement operator which moves the pointer to the previous 04620 * element. */ 04621 iterator operator--(int) 04622 { 04623 Tree::TreeNode* tmp = node; 04624 node = node->decrement(); 04625 return tmp; 04626 } 04627 04628 /** Comparison operator. */ 04629 bool operator==(const iterator& y) const {return node==y.node;} 04630 04631 /** Inequality operator. */ 04632 bool operator!=(const iterator& y) const {return node!=y.node;} 04633 04634 private: 04635 Tree::TreeNode* node; 04636 }; 04637 04638 /** Returns a STL-like iterator to the end of the entity list. */ 04639 static iterator end() {return st.end();} 04640 04641 /** Returns a STL-like iterator to the start of the entity list. */ 04642 static iterator begin() {return st.begin();} 04643 04644 /** Returns false if no named entities have been defined yet. */ 04645 static bool empty() {return st.empty();} 04646 04647 /** Returns the number of defined entities. */ 04648 static size_t size() {return st.size();} 04649 04650 /** Debugging method to verify the validity of the tree. 04651 * An exception is thrown when the tree is corrupted. */ 04652 static void verify() {st.verify();} 04653 04654 /** Deletes all elements from the list. */ 04655 static void clear() {st.clear();} 04656 04657 /** Constructor. */ 04658 explicit HasName(const string& n) : Tree::TreeNode(n) {} 04659 04660 /** Constructor. */ 04661 explicit HasName(const char* n) : Tree::TreeNode(n) {} 04662 04663 /** Rename the entity. */ 04664 void setName(const string& newname) {st.rename(this, newname);} 04665 04666 /** Destructor. */ 04667 ~HasName() {st.erase(this);} 04668 04669 /** Return the name as the string representation in Python. */ 04670 virtual PyObject* str() const {return PythonObject(getName());} 04671 04672 /** Comparison operator for Python. */ 04673 int compare(const PyObject* other) const 04674 { 04675 if (this->ob_type == other->ob_type 04676 || this->ob_type->tp_base == other->ob_type->tp_base) 04677 return getName().compare(static_cast<const T*>(other)->getName()); 04678 else 04679 { 04680 // Different types 04681 PyErr_SetString(PythonDataException, "Wrong type in comparison"); 04682 return -1; 04683 } 04684 } 04685 04686 /** Find an entity given its name. In case it can't be found, a NULL 04687 * pointer is returned. */ 04688 static T* find(const string& k) 04689 { 04690 Tree::TreeNode *i = st.find(k); 04691 return (i!=st.end() ? static_cast<T*>(i) : NULL); 04692 } 04693 04694 /** Find the element with this given key or the element 04695 * immediately preceding it.<br> 04696 * The optional second argument is a boolean that is set to true when 04697 * the element is found in the list. 04698 */ 04699 static T* findLowerBound(const string& k, bool *f = NULL) 04700 { 04701 Tree::TreeNode *i = st.findLowerBound(k, f); 04702 return (i!=st.end() ? static_cast<T*>(i) : NULL); 04703 } 04704 04705 /** Creates a new entity. */ 04706 static T* add(const string& k, const MetaClass& cls) 04707 { 04708 Tree::TreeNode *i = st.find(k); 04709 if (i!=st.end()) return static_cast<T*>(i); // Exists already 04710 if (*(cls.category) != T::metadata) 04711 throw LogicException("Invalid type " + cls.type + 04712 " for creating an object of category " + T::metadata.type); 04713 T *t = dynamic_cast<T*>(cls.factoryMethodString(k)); 04714 st.insert(t); 04715 return t; 04716 } 04717 04718 /** Registers an entity created by the default constructor. */ 04719 static T* add(T* t) {return static_cast<T*>(st.insert(t));} 04720 04721 /** Registers an entity created by the default constructor. The second 04722 * argument is a hint: when passing an entity with a name close to 04723 * the new one, the insertion will be sped up considerably. 04724 */ 04725 static T* add(T* t, T* hint) {return static_cast<T*>(st.insert(t,hint));} 04726 04727 void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement) {}; 04728 04729 /** This method is available as a object creation factory for 04730 * classes that are using a string as a key identifier, in particular 04731 * classes derived from the HasName base class. 04732 * The following attributes are recognized: 04733 * - name:<br> 04734 * Name of the entity to be created/changed/removed.<br> 04735 * The default value is "unspecified". 04736 * - type:<br> 04737 * Determines the subclass to be created.<br> 04738 * The default value is "default". 04739 * - action:<br> 04740 * Determines the action to be performed on the object.<br> 04741 * This can be A (for 'add'), C (for 'change'), AC (for 'add_change') 04742 * or R (for 'remove').<br> 04743 * 'add_change' is the default value. 04744 * @see HasName 04745 */ 04746 static Object* reader (const MetaClass* cat, const AttributeList& in) 04747 { 04748 // Pick up the action attribute 04749 Action act = MetaClass::decodeAction(in); 04750 04751 // Pick up the name attribute. An error is reported if it's missing. 04752 const DataElement* nameElement = in.get(Tags::tag_name); 04753 if (!*nameElement) throw DataException("Missing name attribute"); 04754 string name = nameElement->getString(); 04755 04756 // Check if it exists already 04757 bool found; 04758 T *i = T::findLowerBound(name, &found); 04759 04760 // Validate the action 04761 switch (act) 04762 { 04763 case ADD: 04764 // Only additions are allowed 04765 if (found) 04766 throw DataException("Object '" + name + "' already exists"); 04767 break; 04768 04769 case CHANGE: 04770 // Only changes are allowed 04771 if (!found) 04772 throw DataException("Object '" + name + "' doesn't exist"); 04773 return i; 04774 04775 case REMOVE: 04776 // Delete the entity 04777 if (found) 04778 { 04779 // Send out the notification to subscribers 04780 if (i->getType().raiseEvent(i,SIG_REMOVE)) 04781 { 04782 // Delete the object 04783 delete i; 04784 return NULL; 04785 } 04786 else 04787 // The callbacks disallowed the deletion! 04788 throw DataException("Can't remove object '" + name + "'"); 04789 } 04790 else 04791 // Not found 04792 throw DataException("Can't find object '" + name + "' for removal"); 04793 default: 04794 // case ADD_CHANGE doesn't have special cases. 04795 ; 04796 } 04797 04798 // Return the existing instance 04799 if (found) return i; 04800 04801 // Lookup the type in the map 04802 const MetaClass* j; 04803 if (cat->category) 04804 // Class metadata passed: we already know what type to create 04805 j = cat; 04806 else 04807 { 04808 // Category metadata passed: we need to look up the type 04809 const DataElement* type = in.get(Tags::tag_type); 04810 j = static_cast<const MetaCategory&>(*cat).findClass( 04811 *type ? Keyword::hash(type->getString()) : MetaCategory::defaultHash 04812 ); 04813 if (!j) 04814 { 04815 string t(*type ? type->getString() : "default"); 04816 throw DataException("No type " + t + " registered for category " + cat->type); 04817 } 04818 } 04819 04820 // Create a new instance 04821 T* x = dynamic_cast<T*>(j->factoryMethodString(name)); 04822 04823 // Run creation callbacks 04824 // During the callback there is no write lock set yet, since we can 04825 // assume we are the only ones aware of this new object. We also want 04826 // to make sure the 'add' signal comes before the 'before_change' 04827 // callback that is part of the writelock. 04828 if (!x->getType().raiseEvent(x,SIG_ADD)) 04829 { 04830 // Creation isn't allowed 04831 delete x; 04832 throw DataException("Can't create object " + name); 04833 } 04834 04835 // Insert in the tree 04836 T::add(x, i); 04837 return x; 04838 } 04839 04840 /** A handler that is used to persist the tree. */ 04841 static void writer(const MetaCategory* c, XMLOutput* o) 04842 { 04843 if (empty()) return; 04844 o->BeginObject(*(c->grouptag)); 04845 for (iterator i = begin(); i != end(); ++i) 04846 o->writeElement(*(c->typetag), *i); 04847 o->EndObject(*(c->grouptag)); 04848 } 04849 }; 04850 04851 04852 /** @brief This is a decorator class for the main objects. 04853 * 04854 * Instances of this class have a description, category and sub_category. 04855 */ 04856 class HasDescription 04857 { 04858 public: 04859 /** Returns the category. */ 04860 string getCategory() const {return cat;} 04861 04862 /** Returns the sub_category. */ 04863 string getSubCategory() const {return subcat;} 04864 04865 /** Returns the getDescription. */ 04866 string getDescription() const {return descr;} 04867 04868 /** Sets the category field. */ 04869 void setCategory(const string& f) {cat = f;} 04870 04871 /** Sets the sub_category field. */ 04872 void setSubCategory(const string& f) {subcat = f;} 04873 04874 /** Sets the description field. */ 04875 void setDescription(const string& f) {descr = f;} 04876 04877 void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 04878 void endElement(XMLInput&, const Attribute&, const DataElement&); 04879 04880 protected: 04881 /** Returns the memory size in bytes. */ 04882 size_t extrasize() const {return cat.size() + subcat.size() + descr.size();} 04883 04884 private: 04885 string cat; 04886 string subcat; 04887 string descr; 04888 }; 04889 04890 04891 /** @brief This is a base class for the main objects. 04892 * 04893 * Instances of this class have the following properties: 04894 * - Unique name and global hashtable are inherited from the class HasName. 04895 * - Instances build up hierarchical trees of arbitrary depth. 04896 * - Each object can have a single parent only. 04897 * - Each object has a parent and can have children. 04898 * This class thus implements the 'composite' design pattern. 04899 * The internal data structure is a singly linked linear list, which is 04900 * efficient provided the number of childre remains limited. 04901 */ 04902 template <class T> class HasHierarchy : public HasName<T> 04903 { 04904 #if (defined _MSC_VER) || (defined __BORLANDC__) 04905 // Visual C++ 6.0 and Borland C++ 5.5 seem to get confused with the private 04906 // template members 04907 friend class HasHierarchy<T>; 04908 #endif 04909 04910 public: 04911 class memberIterator; 04912 friend class memberIterator; 04913 /** @brief This class models an STL-like iterator that allows us to 04914 * iterate over the members. 04915 * 04916 * Objects of this class are created by the beginMember() method. 04917 */ 04918 class memberIterator 04919 { 04920 public: 04921 /** Constructor to iterate over member entities. */ 04922 memberIterator(const HasHierarchy<T>* x) : member_iter(true) 04923 {curmember = const_cast<HasHierarchy<T>*>(x)->first_child;} 04924 04925 /** Constructor to iterate over all entities. */ 04926 memberIterator() : curmember(&*T::begin()), member_iter(false) {} 04927 04928 /** Constructor. */ 04929 memberIterator(const typename HasName<T>::iterator& it) : curmember(&*it), member_iter(false) {} 04930 04931 /** Copy constructor. */ 04932 memberIterator(const memberIterator& it) 04933 { 04934 curmember = it.curmember; 04935 member_iter = it.member_iter; 04936 } 04937 04938 /** Return the content of the current node. */ 04939 T& operator*() const {return *static_cast<T*>(curmember);} 04940 04941 /** Return the content of the current node. */ 04942 T* operator->() const {return static_cast<T*>(curmember);} 04943 04944 /** Pre-increment operator which moves the pointer to the next member. */ 04945 memberIterator& operator++() 04946 { 04947 if (member_iter) 04948 curmember = curmember->next_brother; 04949 else 04950 curmember = static_cast<T*>(curmember->increment()); 04951 return *this; 04952 } 04953 04954 /** Post-increment operator which moves the pointer to the next member. */ 04955 memberIterator operator++(int) 04956 { 04957 memberIterator tmp = *this; 04958 if (member_iter) 04959 curmember = curmember->next_brother; 04960 else 04961 curmember = static_cast<T*>(curmember->increment()); 04962 return tmp; 04963 } 04964 04965 /** Comparison operator. */ 04966 bool operator==(const memberIterator& y) const 04967 {return curmember == y.curmember;} 04968 04969 /** Inequality operator. */ 04970 bool operator!=(const memberIterator& y) const 04971 {return curmember != y.curmember;} 04972 04973 /** Comparison operator. */ 04974 bool operator==(const typename HasName<T>::iterator& y) const 04975 {return curmember ? (curmember == &*y) : (y == T::end());} 04976 04977 /** Inequality operator. */ 04978 bool operator!=(const typename HasName<T>::iterator& y) const 04979 {return curmember ? (curmember != &*y) : (y != T::end());} 04980 04981 private: 04982 /** Points to a member. */ 04983 HasHierarchy<T>* curmember; 04984 bool member_iter; 04985 }; 04986 04987 /** The one and only constructor. */ 04988 HasHierarchy(const string& n) : HasName<T>(n), parent(NULL), 04989 first_child(NULL), next_brother(NULL) {} 04990 04991 /** Destructor. 04992 * When deleting a node of the hierarchy, the children will get the 04993 * current parent as the new parent. 04994 * In this way the deletion of nodes doesn't create "dangling branches" 04995 * in the hierarchy. We just "collapse" a certain level. 04996 */ 04997 ~HasHierarchy(); 04998 04999 /** Return a member iterator. */ 05000 memberIterator beginMember() const {return this;} 05001 05002 /** Returns true if this entity belongs to a higher hierarchical level.<br> 05003 * An entity can have only a single owner, and can't belong to multiple 05004 * hierarchies. 05005 */ 05006 bool hasOwner() const {return parent!=NULL;} 05007 05008 /** Returns true if this entity has lower level entities belonging to 05009 * it. */ 05010 bool isGroup() const {return first_child!=NULL;} 05011 05012 /** Changes the owner of the entity.<br> 05013 * The argument must be a valid pointer to an entity of the same type.<br> 05014 * A NULL pointer can be passed to clear the existing owner.<br> 05015 */ 05016 void setOwner(T* f); 05017 05018 /** Returns the owning entity. */ 05019 T* getOwner() const {return parent;} 05020 05021 /** Returns the level in the hierarchy.<br> 05022 * Level 0 means the entity doesn't have any parent.<br> 05023 * Level 1 means the entity has a parent entity with level 0.<br> 05024 * Level "x" means the entity has a parent entity whose level is "x-1". 05025 */ 05026 unsigned short getHierarchyLevel() const; 05027 05028 void beginElement(XMLInput&, const Attribute&); 05029 void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 05030 void endElement(XMLInput&, const Attribute&, const DataElement&); 05031 05032 private: 05033 /** A pointer to the parent object. */ 05034 T *parent; 05035 05036 /** A pointer to the first child object. */ 05037 T *first_child; 05038 05039 /** A pointer to the next brother object, ie an object having the 05040 * same parent.<br> 05041 * The brothers are all linked as a single linked list, with the 05042 * first_child pointer on the parent being the root pointer of the list. 05043 */ 05044 T *next_brother; 05045 }; 05046 05047 05048 // 05049 // ASSOCIATION 05050 // 05051 05052 /** @brief This template class represents a data structure for a load or flow 05053 * network. 05054 * 05055 * A node class has pointers to 2 root classes.<br> The 2 root classes each 05056 * maintain a singly linked list of nodes.<br> 05057 * An example to clarify the usage: 05058 * - class "node" = a newspaper subscription. 05059 * - class "person" = maintains a list of all his subscriptions. 05060 * - class "newspaper" = maintains a list of all subscriptions for it. 05061 * 05062 * This data structure could be replaced with 2 linked lists, but this 05063 * specialized data type consumes considerably lower memory. 05064 * 05065 * Reading from the structure is safe in multi-threading mode.<br> 05066 * Updates to the data structure in a multi-threading mode require the user 05067 * to properly lock and unlock the container. 05068 */ 05069 template <class A, class B, class C> class Association 05070 { 05071 public: 05072 class Node; 05073 private: 05074 /** @brief A abstract base class for the internal representation of the 05075 * association lists. 05076 */ 05077 class List 05078 { 05079 friend class Node; 05080 public: 05081 C* first; 05082 public: 05083 List() : first(NULL) {}; 05084 bool empty() const {return first==NULL;} 05085 }; 05086 05087 public: 05088 /** @brief A list type of the "first" / "from" part of the association. */ 05089 class ListA : public List 05090 { 05091 public: 05092 ListA() {}; 05093 /** @brief An iterator over the associated objects. */ 05094 class iterator 05095 { 05096 protected: 05097 C* nodeptr; 05098 public: 05099 iterator(C* n) : nodeptr(n) {}; 05100 C& operator*() const {return *nodeptr;} 05101 C* operator->() const {return nodeptr;} 05102 bool operator==(const iterator& x) const 05103 {return nodeptr == x.nodeptr;} 05104 bool operator!=(const iterator& x) const 05105 {return nodeptr != x.nodeptr;} 05106 iterator& operator++() 05107 {nodeptr = nodeptr->nextA; return *this;} 05108 iterator operator++(int i) 05109 { 05110 iterator j = *this; 05111 nodeptr = nodeptr->nextA; 05112 return j; 05113 } 05114 }; 05115 /** @brief An iterator over the associated objects. */ 05116 class const_iterator 05117 { 05118 protected: 05119 C* nodeptr; 05120 public: 05121 const_iterator(C* n) : nodeptr(n) {}; 05122 const C& operator*() const {return *nodeptr;} 05123 const C* operator->() const {return nodeptr;} 05124 bool operator==(const const_iterator& x) const 05125 {return nodeptr == x.nodeptr;} 05126 bool operator!=(const const_iterator& x) const 05127 {return nodeptr != x.nodeptr;} 05128 const_iterator& operator++() 05129 {nodeptr = nodeptr->nextA; return *this;} 05130 const_iterator operator++(int i) 05131 { 05132 const_iterator j = *this; 05133 nodeptr = nodeptr->nextA; 05134 return j; 05135 } 05136 }; 05137 iterator begin() {return iterator(this->first);} 05138 const_iterator begin() const {return const_iterator(this->first);} 05139 iterator end() {return iterator(NULL);} 05140 const_iterator end() const {return const_iterator(NULL);} 05141 05142 /** Destructor. */ 05143 ~ListA() 05144 { 05145 C* next; 05146 for (C* p=this->first; p; p=next) 05147 { 05148 next = p->nextA; 05149 delete p; 05150 } 05151 } 05152 05153 /** Remove an association. */ 05154 void erase(const C* n) 05155 { 05156 if (!n) return; 05157 if (n==this->first) 05158 this->first = n->nextA; 05159 else 05160 for (C* p=this->first; p; p=p->nextA) 05161 if(p->nextA == n) 05162 { 05163 p->nextA = n->nextA; 05164 return; 05165 } 05166 } 05167 05168 /** Return the number of associations. */ 05169 size_t size() const 05170 { 05171 size_t i(0); 05172 for (C* p = this->first; p; p=p->nextA) ++i; 05173 return i; 05174 } 05175 05176 /** Search for the association effective at a certain date. */ 05177 C* find(const B* b, Date d = Date::infinitePast) const 05178 { 05179 for (C* p=this->first; p; p=p->nextA) 05180 if (p->ptrB == b && p->effectivity.within(d)) return p; 05181 return NULL; 05182 } 05183 05184 /** Search for the association with a certain name. */ 05185 C* find(const string& n) const 05186 { 05187 for (C* p=this->first; p; p=p->nextA) 05188 if (p->name == n) return p; 05189 return NULL; 05190 } 05191 05192 /** Move an association a position up in the list of associations. */ 05193 void promote(C* p) 05194 { 05195 // Already at the head 05196 if (p == this->first) return; 05197 05198 // Scan the list 05199 C* prev = NULL; 05200 for (C* ptr = this->first; ptr; ptr = ptr->nextA) 05201 { 05202 if (ptr->nextA == p) 05203 { 05204 if (prev) 05205 prev->nextA = p; 05206 else 05207 this->first = p; 05208 ptr->nextA = p->nextA; 05209 p->nextA = ptr; 05210 return; 05211 } 05212 prev = ptr; 05213 } 05214 throw LogicException("Association not found in the list"); 05215 } 05216 }; 05217 05218 /** @brief A list type of the "second" / "to" part of the association. */ 05219 class ListB : public List 05220 { 05221 public: 05222 ListB() {}; 05223 /** @brief An iterator over the associated objects. */ 05224 class iterator 05225 { 05226 protected: 05227 C* nodeptr; 05228 public: 05229 iterator(C* n) : nodeptr(n) {}; 05230 C& operator*() const {return *nodeptr;} 05231 C* operator->() const {return nodeptr;} 05232 bool operator==(const iterator& x) const 05233 {return nodeptr == x.nodeptr;} 05234 bool operator!=(const iterator& x) const 05235 {return nodeptr != x.nodeptr;} 05236 iterator& operator++() 05237 {nodeptr = nodeptr->nextB; return *this;} 05238 iterator operator++(int i) 05239 { 05240 iterator j = *this; 05241 nodeptr = nodeptr->nextA; 05242 return j; 05243 } 05244 }; 05245 /** @brief An iterator over the associated objects. */ 05246 class const_iterator 05247 { 05248 protected: 05249 C* nodeptr; 05250 public: 05251 const_iterator(C* n) : nodeptr(n) {}; 05252 const C& operator*() const {return *nodeptr;} 05253 const C* operator->() const {return nodeptr;} 05254 bool operator==(const const_iterator& x) const 05255 {return nodeptr == x.nodeptr;} 05256 bool operator!=(const const_iterator& x) const 05257 {return nodeptr != x.nodeptr;} 05258 const_iterator& operator++() 05259 {nodeptr = nodeptr->nextB; return *this;} 05260 const_iterator operator++(int i) 05261 { 05262 const_iterator j = *this; 05263 nodeptr = nodeptr->nextA; 05264 return j; 05265 } 05266 }; 05267 05268 /** Destructor. */ 05269 ~ListB() 05270 { 05271 C* next; 05272 for (C* p=this->first; p; p=next) 05273 { 05274 next = p->nextB; 05275 delete p; 05276 } 05277 } 05278 iterator begin() {return iterator(this->first);} 05279 const_iterator begin() const {return const_iterator(this->first);} 05280 iterator end() {return iterator(NULL);} 05281 const_iterator end() const {return const_iterator(NULL);} 05282 05283 /** Remove an association. */ 05284 void erase(const C* n) 05285 { 05286 if (!n) return; 05287 if (n==this->first) 05288 this->first = n->nextB; 05289 else 05290 for (C* p=this->first; p; p=p->nextB) 05291 if(p->nextB == n) 05292 { 05293 p->nextB = n->nextB; 05294 return; 05295 } 05296 } 05297 05298 /** Return the number of associations. */ 05299 size_t size() const 05300 { 05301 size_t i(0); 05302 for (C* p=this->first; p; p=p->nextB) ++i; 05303 return i; 05304 } 05305 05306 /** Search for the association effective at a certain date. */ 05307 C* find(const A* b, Date d = Date::infinitePast) const 05308 { 05309 for (C* p=this->first; p; p=p->nextB) 05310 if (p->ptrA == b && p->effectivity.within(d)) return p; 05311 return NULL; 05312 } 05313 05314 /** Search for the association with a certain name. */ 05315 C* find(const string& n) const 05316 { 05317 for (C* p=this->first; p; p=p->nextB) 05318 if (p->name == n) return p; 05319 return NULL; 05320 } 05321 05322 /** Move an association a position up in the list of associations. */ 05323 void promote(C* p) 05324 { 05325 // Already at the head 05326 if (p == this->first) return; 05327 05328 // Scan the list 05329 C* prev = NULL; 05330 for (C* ptr = this->first; ptr; ptr = ptr->nextB) 05331 { 05332 if (ptr->nextB == p) 05333 { 05334 if (prev) 05335 prev->nextB = p; 05336 else 05337 this->first = p; 05338 ptr->nextB = p->nextB; 05339 p->nextB = ptr; 05340 return; 05341 } 05342 prev = ptr; 05343 } 05344 throw LogicException("Association not found in the list"); 05345 } 05346 }; 05347 05348 /** @brief A base class for the class representing the association 05349 * itself. 05350 */ 05351 class Node 05352 { 05353 public: 05354 A* ptrA; 05355 B* ptrB; 05356 C* nextA; 05357 C* nextB; 05358 DateRange effectivity; 05359 string name; 05360 public: 05361 /** Constructor. */ 05362 Node() : ptrA(NULL), ptrB(NULL), nextA(NULL), nextB(NULL) {}; 05363 05364 /** Constructor. */ 05365 Node(A* a, B* b, const ListA& al, const ListB& bl) 05366 : ptrA(a), ptrB(b), nextA(NULL), nextB(NULL) 05367 { 05368 if (al.first) 05369 { 05370 // Append at the end of the A-list 05371 C* x = al.first; 05372 while (x->nextA) x = x->nextA; 05373 x->nextA = static_cast<C*>(this); 05374 } 05375 else 05376 // New start of the A-list 05377 const_cast<ListA&>(al).first = static_cast<C*>(this); 05378 if (bl.first) 05379 { 05380 // Append at the end of the B-list 05381 C* x = bl.first; 05382 while (x->nextB) x = x->nextB; 05383 x->nextB = static_cast<C*>(this); 05384 } 05385 else 05386 // New start of the B-list 05387 const_cast<ListB&>(bl).first = static_cast<C*>(this); 05388 } 05389 05390 void setPtrA(A* a, const ListA& al) 05391 { 05392 // Don't allow updating an already valid link 05393 if (ptrA) throw DataException("Can't update existing entity"); 05394 ptrA = a; 05395 if (al.first) 05396 { 05397 // Append at the end of the A-list 05398 C* x = al.first; 05399 while (x->nextA) x = x->nextA; 05400 x->nextA = static_cast<C*>(this); 05401 } 05402 else 05403 // New start of the A-list 05404 const_cast<ListA&>(al).first = static_cast<C*>(this); 05405 } 05406 05407 void setPtrB(B* b, const ListB& bl) 05408 { 05409 // Don't allow updating an already valid link 05410 if (ptrB) throw DataException("Can't update existing entity"); 05411 ptrB = b; 05412 if (bl.first) 05413 { 05414 // Append at the end of the B-list 05415 C* x = bl.first; 05416 while (x->nextB) x = x->nextB; 05417 x->nextB = static_cast<C*>(this); 05418 } 05419 else 05420 // New start of the B-list 05421 const_cast<ListB&>(bl).first = static_cast<C*>(this); 05422 } 05423 05424 void setPtrAB(A* a, B* b, const ListA& al, const ListB& bl) 05425 { 05426 setPtrA(a, al); 05427 setPtrB(b, bl); 05428 } 05429 05430 A* getPtrA() const {return ptrA;} 05431 05432 B* getPtrB() const {return ptrB;} 05433 05434 /** Update the start date of the effectivity range. */ 05435 void setEffectiveStart(Date d) {effectivity.setStart(d);} 05436 05437 /** Update the end date of the effectivity range. */ 05438 void setEffectiveEnd(Date d) {effectivity.setEnd(d);} 05439 05440 /** Update the effectivity range. */ 05441 void setEffective(DateRange dr) {effectivity = dr;} 05442 05443 /** Return the effectivity daterange.<br> 05444 * The default covers the complete time horizon. 05445 */ 05446 DateRange getEffective() const {return effectivity;} 05447 05448 /** Sets an optional name for the association.<br> 05449 * There is no garantuee of the uniqueness of this name. 05450 */ 05451 void setName(const string x) {name = x;} 05452 05453 /** Return the optional name of the association. */ 05454 const string& getName() const {return name;} 05455 }; 05456 }; 05457 05458 05459 #include "frepple/entity.h" 05460 05461 05462 // 05463 // LIBRARY INITIALISATION 05464 // 05465 05466 /** @brief This class holds functions that used for maintenance of the library. 05467 * 05468 * Its static member function 'initialize' should be called BEFORE the 05469 * first use of any class in the library. 05470 * The member function 'finialize' will be called automatically at the 05471 * end of the program. 05472 */ 05473 class LibraryUtils 05474 { 05475 public: 05476 static void initialize(int argc, char* argv[]); 05477 }; 05478 05479 /** @brief A template class to expose iterators to Python. */ 05480 template <class ME, class ITERCLASS, class DATACLASS> 05481 class FreppleIterator : public PythonExtension<ME> 05482 { 05483 public: 05484 static int initialize() 05485 { 05486 // Initialize the type 05487 PythonType& x = PythonExtension<ME>::getType(); 05488 x.setName(DATACLASS::metadata->type + "Iterator"); 05489 x.setDoc("frePPLe iterator for " + DATACLASS::metadata->type); 05490 x.supportiter(); 05491 return x.typeReady(); 05492 } 05493 05494 FreppleIterator() : i(DATACLASS::begin()) 05495 {this->initType(PythonExtension<ME>::getType().type_object());} 05496 05497 template <class OTHER> FreppleIterator(const OTHER *o) : i(o) 05498 {this->initType(PythonExtension<ME>::getType().type_object());} 05499 05500 template <class OTHER> FreppleIterator(const OTHER &o) : i(o) 05501 {this->initType(PythonExtension<ME>::getType().type_object());} 05502 05503 static PyObject* create(PyObject* self, PyObject* args) 05504 {return new ME();} 05505 05506 private: 05507 ITERCLASS i; 05508 05509 virtual PyObject* iternext() 05510 { 05511 if (i == DATACLASS::end()) return NULL; 05512 PyObject* result = &*i; 05513 ++i; 05514 Py_INCREF(result); 05515 return result; 05516 } 05517 }; 05518 05519 /** @brief This Python function loads a frepple extension module in memory. */ 05520 DECLARE_EXPORT PyObject* loadModule(PyObject*, PyObject*, PyObject*); 05521 05522 05523 } // end namespace 05524 } // end namespace 05525 05526 #include "pythonutils.h" 05527 05528 #endif // End of FREPPLE_UTILS_H