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