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