diff --git a/cpp/Barbershop/Doxyfile b/cpp/Barbershop/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..3ffb5e884143b7ae9a3fa1e3e337d83fcfe7c121 --- /dev/null +++ b/cpp/Barbershop/Doxyfile @@ -0,0 +1,2454 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Barbershop + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = /usr/local/bin/dot + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/cpp/Barbershop/Makefile b/cpp/Barbershop/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..705f72461731871514ec597b5c4dd83b46078871 --- /dev/null +++ b/cpp/Barbershop/Makefile @@ -0,0 +1,27 @@ +ODEMX_HOME := ../ODEMx-lite + +CFLAGS := -std=c++14 -O3 -flto -I$(ODEMX_HOME)/include -I$(ODEMX_HOME)/external/CppLog/include +LFLAGS := -L$(ODEMX_HOME)/lib + +CPPFILES := $(wildcard *.cpp) +HPPFILES := $(wildcard *.h) $(wildcard *.hpp) + +LIBS := -lOdemx +OBJS := $(CPPFILES:%.cpp=%.o) +TARGET := Barbershop + +# compile +%.o: %.cpp + $(CXX) $(CFLAGS) -c $< -o $@ + +# link +all: $(OBJS) + $(CXX) $(LFLAGS) $^ $(LIBS) -o $(TARGET) + +# run +run: all + ./$(TARGET) + +# clean +clean: + $(RM) $(RMFILES) $(OBJS) $(TARGET) diff --git a/cpp/Barbershop/main.cpp b/cpp/Barbershop/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70eb7f452a7035ecea311747479344dd66d47721 --- /dev/null +++ b/cpp/Barbershop/main.cpp @@ -0,0 +1,159 @@ + +#include <odemx/odemx.h> +#include <vector> +#include <memory> +#include <iostream> + +using odemx::base::SimTime; +using odemx::base::Process; +using odemx::base::Simulation; +using odemx::synchronization::Bin; +using odemx::random::Uniform; +using odemx::statistics::Tally; +using odemx::data::output::OStreamReport; + +// helper constants +const SimTime SIM_DURATION = 24.0*60.0*7.0*3.0; + +namespace Barbershop { + ///@brief A barbershop-specific simulation class. + struct Sim: Simulation { + ///@brief The barber that can only serve one customer concurrently. + Bin joe; + ///@brief Statistics collection for the time customers spend waiting. + Tally wait_time; + ///@brief Pointer to the main process. + std::unique_ptr<Process> main; + + ///@brief Initializes the main process and the other attributes. + Sim(SimTime duration); + + protected: + ///@brief Automatically called method activating the main process. + void initSimulation() override { + main->activate(); + } + }; + + ///@brief Active customer trying to get a haircut from Joe. + class Customer: public Process { + ///@brief The amount of time needed by Joe to serve this customer once + /// it is their turn. + SimTime delay; + + public: + ///@brief Constructor. + Customer(Sim& sim, SimTime delay) + : Process(sim, "Customer"), + delay(delay) {} + + ///@brief Method containing the lifecycle of the customer. + int main() override { + Sim& sim = static_cast<Sim&>(getSimulation()); + + // access the barber and record the time for the report + SimTime arrival_time = getTime(); + sim.joe.take(1); + sim.wait_time.update(getTime() - arrival_time); + + // spend time + holdFor(delay); + // release the barber + sim.joe.give(1); + + return 0; + } + }; + + ///@brief The process responsible for generating customers. + class CustomerGenerator: public Process { + ///@brief A list of all the customers generated by this process. + std::vector<std::unique_ptr<Customer>> customers; + + public: + ///@brief The constructor. + CustomerGenerator(Sim& sim): Process(sim, "Customer Generator") {} + + ///@brief Method containing the lifecycle of the customer generator. + int main() override { + Sim& sim = static_cast<Sim&>(getSimulation()); + Uniform dist_a(sim, "Time between customers", 12.0, 24.0); + Uniform dist_s(sim, "Time for each customer", 12.0, 18.0); + + while (true) { + holdFor(dist_a.sample()); + customers.push_back(std::make_unique<Customer>( + sim, dist_s.sample() + )); + customers.back()->activate(); + } + + return 0; + } + }; + + ///@brief The main process. + class Main: public Process { + ///@brief Time between opening and closing the shop. + SimTime duration; + ///@brief Internal customer generator process. + CustomerGenerator generator; + + public: + ///@brief The constructor. + Main(Sim& sim, SimTime duration) + : Process(sim, "Main Process"), + duration(duration), + generator(sim) + {} + + ///@brief The method containing the lifecycle of the main process. + int main() override { + // activate a process to generate the customers + generator.activate(); + + // wait until the store closes + holdFor(duration); + generator.cancel(); + + // finish processing the queue (no more customers arrive) + return 0; + } + }; + + // Simulation constructor moved down here to prevent backwards references. + Sim::Sim(SimTime duration) + : Simulation("Barbershop"), + joe(*this, "Joe", 1), + wait_time(*this, "Wait Time"), + main(std::make_unique<Main>(*this, duration)) + {} +} + +#ifdef RUST_FFI +///@brief Entry point for the function used to benchmark this scenario. +extern "C" void barbershop(SimTime duration) { + // set up the simulation model + Barbershop::Sim sim(duration); + + // run to completion + sim.run(); + + // no report +} +#else +int main() { + // set up the simulation model + Barbershop::Sim sim(SIM_DURATION); + + // run to completion + sim.run(); + + // generate the report + OStreamReport report(std::cout); + report.addReportProducer(sim.wait_time); + report.generateReport(); + + return 0; +} +#endif diff --git a/cpp/Ferry/Doxyfile b/cpp/Ferry/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..0b1be5b603d95cba3d0775435d70967f7b6a71e6 --- /dev/null +++ b/cpp/Ferry/Doxyfile @@ -0,0 +1,2454 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Ferry + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = /usr/local/bin/dot + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/cpp/Ferry/Makefile b/cpp/Ferry/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b4b865b1e31b917a8ae95266b512224c8297f472 --- /dev/null +++ b/cpp/Ferry/Makefile @@ -0,0 +1,27 @@ +ODEMX_HOME := ../ODEMx-lite + +CFLAGS := -std=c++14 -O3 -flto -I$(ODEMX_HOME)/include -I$(ODEMX_HOME)/external/CppLog/include +LFLAGS := -L$(ODEMX_HOME)/lib + +CPPFILES := $(wildcard *.cpp) +HPPFILES := $(wildcard *.h) $(wildcard *.hpp) + +LIBS := -lOdemx +OBJS := $(CPPFILES:%.cpp=%.o) +TARGET := Ferry + +# compile +%.o: %.cpp + $(CXX) $(CFLAGS) -c $< -o $@ + +# link +all: $(OBJS) + $(CXX) $(LFLAGS) $^ $(LIBS) -o $(TARGET) + +# run +run: all + ./$(TARGET) + +# clean +clean: + $(RM) $(RMFILES) $(OBJS) $(TARGET) diff --git a/cpp/Ferry/main.cpp b/cpp/Ferry/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd0b483ebaf00e589adc98dd5a22d5f63757f49a --- /dev/null +++ b/cpp/Ferry/main.cpp @@ -0,0 +1,285 @@ + +#include <odemx/odemx.h> +#include <vector> +#include <memory> +#include <iostream> +#include <utility> + +using odemx::base::SimTime; +using odemx::base::Process; +using odemx::base::Simulation; +using odemx::synchronization::PortHeadT; +using odemx::synchronization::PortTailT; +using odemx::synchronization::Timer; +using odemx::synchronization::IMemory; +using odemx::random::NegativeExponential; +using odemx::random::Normal; +using odemx::statistics::Tally; + +const SimTime SIM_DURATION = 24.0*60.0*7.0; +const SimTime HARBOR_DISTANCE = 10.0; +const SimTime FERRY_TIMEOUT = 5.0; +const unsigned int FERRY_CAPACITY = 5; +const unsigned int FERRY_COUNT = 2; +const unsigned int HARBOR_COUNT = 4; + +namespace Ferry { + // forward declarations + struct Car; + class Pier; + class Ferry; + + // These are just ODEMx-flavored sender/receiver-pairs for the same channel. + typedef odemx::synchronization::PortTailT<Car> PortTail; + typedef odemx::synchronization::PortHeadT<Car> PortHead; + + ///@brief A car-ferry-specific simulation class. + class Sim: public Simulation { + ///@brief A vector for all of the harbors. + std::vector<std::unique_ptr<Pier>> piers; + ///@brief A vector for all of the ferries. + std::vector<std::unique_ptr<Ferry>> ferries; + + public: + ///@brief Constructor setting up the number of harbors and ferries. + Sim(unsigned int ferries, unsigned int harbors); + + ///@brief Cleans up the model by accounting for all of the remaining + /// cars of the harbors. + void finalize(); + + ///@brief Statistical aggregations. + Tally ferry_cargo_len; + Tally ferry_load_time; + Tally car_wait_time; + + protected: + ///@brief Automatically called method activating all of the ferries and + /// harbors. + void initSimulation() override; + }; + + ///@brief A passive structure for cars. + struct Car { + SimTime arrival_time; + SimTime load_duration; + }; + + ///@brief The process modeling a harbor with arriving cars. + class Pier: public Process { + ///@brief Writing end for the queue with arriving cars. + PortTail::Ptr landing_site; + + ///@brief Returns an upcasted version of the basic simulation. + Sim& getSimulation() { + return static_cast<Sim&>(Process::getSimulation()); + } + + public: + ///@brief The constructor initializing the car queue. + Pier(Sim& sim) + : Process(sim, "Harbor"), + landing_site(PortTail::create(sim, "Harbor Port")) + {} + + ///@brief Cleans up the harbor by accounting for all of the cars that + /// are still waiting for a ferry. + void finalize() { + unsigned int count = landing_site->count(); + PortHead::Ptr head = landing_site->getHead(); + Sim& sim = getSimulation(); + + // take cars into account that weren't picked up by a ferry + for (unsigned int i = 0; i < count; ++i) { + sim.car_wait_time.update(sim.getTime() - head->get()->arrival_time); + } + } + + ///@brief Method providing access to the reading end of the car queue. + inline PortHead::Ptr getHead() { + return landing_site->getHead(); + } + + ///@brief Models the lifecycle of the harbor. + int main() override { + NegativeExponential arrival_delay(getSimulation(), "Arrival Delay", 0.1); + Normal loading_delay(getSimulation(), "Loading Delay", 0.5, 0.2); + + while (true) { + double load_duration; + + holdFor(arrival_delay.sample()); + + do load_duration = loading_delay.sample(); + while (load_duration < 0.0); + + landing_site->put(Car { + getTime(), load_duration + }); + } + + return 0; + } + }; + + ///@brief The process modeling an individual ferry. + class Ferry: public Process { + ///@brief Space for the cars. + std::vector<Car> cargo; + ///@brief Maximum car capacity. + unsigned int capacity; + ///@brief Time to wait for another car before leaving before filling all + /// of the available cargo space. + SimTime timeout; + ///@brief Travel time between (any) two harbors. + SimTime travel_time; + ///@brief Vector of reading ends for all of the harbors. + std::vector<PortHead::Ptr> piers; + + ///@brief Returns an upcasted version of the basic simulation. + Sim& getSimulation() { + return static_cast<Sim&>(Process::getSimulation()); + } + + public: + ///@brief Constructor. + Ferry(Sim& sim, unsigned int capacity, + SimTime timeout, SimTime travel_time, + std::vector<PortHead::Ptr>&& piers) + : Process(sim, "Ferry"), + capacity(capacity), + timeout(timeout), + travel_time(travel_time), + piers(piers) + {} + + ///@brief Models the lifecycle of the ferry. + int main() override { + Timer timer(getSimulation(), "FerryTimer"); + IMemory* notifier; + Car car; + + while (true) { + for (auto& pier: piers) { + // unload the cars + for (auto& car: cargo) { + holdFor(car.load_duration); + } + cargo.clear(); + + SimTime begin_loading = getTime(); + + // wait until new cars arrive or a timeout occurs + while (cargo.size() < capacity) { + timer.setIn(timeout); + notifier = wait(&timer, pier.get()); + + if (notifier != &timer) { + // a car arrived in time + car = *pier->get(); + timer.stop(); + getSimulation() + .car_wait_time + .update(getTime() - car.arrival_time); + holdFor(car.load_duration); + cargo.push_back(car); + } else { + // the timeout has been triggered + break; + } + } + + getSimulation() + .ferry_load_time + .update(getTime() - begin_loading); + getSimulation() + .ferry_cargo_len + .update(cargo.size()); + + // travel to the next harbor + holdFor(travel_time); + } + } + + return 0; + } + }; + + // Implementation of the simulation class. + + Sim::Sim(unsigned int ferries, unsigned int harbors) + : Simulation("Ferry"), + ferry_cargo_len(*this, "Ferry Cargo Len"), + ferry_load_time(*this, "Ferry Load Time"), + car_wait_time(*this, "Car Wait Time") + { + // create all of the harbors + for (unsigned int i = 0; i < harbors; ++i) { + piers.push_back(std::make_unique<Pier>(*this)); + } + + // create all of the ferries + for (unsigned int i = 0; i < ferries; ++i) { + std::vector<PortHead::Ptr> ports; + + for (unsigned int j = i; j < harbors; ++j) { + ports.push_back(piers[j]->getHead()); + } + + for (unsigned int j = 0; j < i; ++j) { + ports.push_back(piers[j]->getHead()); + } + + this->ferries.push_back(std::make_unique<Ferry>( + *this, FERRY_CAPACITY, FERRY_TIMEOUT, HARBOR_DISTANCE, + std::move(ports) + )); + } + } + + void Sim::finalize() { + for (auto& pier: piers) { + pier->finalize(); + } + } + + void Sim::initSimulation() { + // activate the harbors + for (auto& pier: piers) { + pier->activate(); + } + + // activate the ferries + for (auto& ferry: ferries) { + ferry->activate(); + } + } +} + +#ifdef RUST_FFI +///@brief Entry point for the function used to benchmark this scenario. +extern "C" void ferry(SimTime duration, unsigned int ferries, unsigned int harbors) { + // set up the simulation model + Ferry::Sim sim(ferries, harbors); + sim.runUntil(duration); + sim.finalize(); + + // no report +} +#else +int main() { + // set up the simulation model + Ferry::Sim sim(FERRY_COUNT, HARBOR_COUNT); + sim.runUntil(SIM_DURATION); + sim.finalize(); + + // generate the report + odemx::data::output::OStreamReport report(std::cout); + report.addReportProducer(sim.ferry_cargo_len); + report.addReportProducer(sim.ferry_load_time); + report.addReportProducer(sim.car_wait_time); + report.generateReport(); + + return 0; +} +#endif diff --git a/cpp/Philosophers/Doxyfile b/cpp/Philosophers/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..cf78a3ea099c13777782b8050caaa15c36df3e8a --- /dev/null +++ b/cpp/Philosophers/Doxyfile @@ -0,0 +1,2454 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Dining Philosophers + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = /usr/local/bin/dot + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/cpp/Philosophers/Makefile b/cpp/Philosophers/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2f149051de7cab38af11404ef0bc8eb97cc537e2 --- /dev/null +++ b/cpp/Philosophers/Makefile @@ -0,0 +1,27 @@ +ODEMX_HOME := ../ODEMx-lite + +CFLAGS := -std=c++14 -O3 -flto -I$(ODEMX_HOME)/include -I$(ODEMX_HOME)/external/CppLog/include +LFLAGS := -L$(ODEMX_HOME)/lib + +CPPFILES := $(wildcard *.cpp) +HPPFILES := $(wildcard *.h) $(wildcard *.hpp) + +LIBS := -lOdemx +OBJS := $(CPPFILES:%.cpp=%.o) +TARGET := Philosophers + +# compile +%.o: %.cpp + $(CXX) $(CFLAGS) -c $< -o $@ + +# link +all: $(OBJS) + $(CXX) $(LFLAGS) $^ $(LIBS) -o $(TARGET) + +# run +run: all + ./$(TARGET) + +# clean +clean: + $(RM) $(RMFILES) $(OBJS) $(TARGET) diff --git a/cpp/Philosophers/main.cpp b/cpp/Philosophers/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e137beb22216427b65eebae00a99764a1f064cae --- /dev/null +++ b/cpp/Philosophers/main.cpp @@ -0,0 +1,169 @@ +#include <odemx/odemx.h> +#include <iostream> +#include <vector> +#include <memory> + +const int PHILOSOPHER_COUNT = 5; +const int EXPERIMENT_COUNT = 500; + +using odemx::base::Simulation; +using odemx::base::Process; +using odemx::synchronization::Bin; +using odemx::statistics::Tally; +using odemx::data::output::OStreamReport; + +namespace Philosophers { + ///@brief Passive class used to model the table that the philosophers are + /// seated around + class Table { + ///@brief A vector for the forks. + std::vector<std::unique_ptr<Bin>> forks; + + public: + ///@brief Constructor initializing the fork-vector. + Table(Simulation& sim, unsigned int forks) { + for (int i = 0; i < forks; ++i) { + this->forks.push_back(std::make_unique<Bin>(sim, "Fork", 1)); + } + } + + ///@brief Blocks until the requested fork is available and acquires it. + void acquire_fork(unsigned int i) { + i %= forks.size(); + forks[i]->take(1); + } + + ///@brief Returns the requested fork (presumably wiped clean) to the + /// table. + void release_fork(unsigned int i) { + i %= forks.size(); + forks[i]->give(1); + } + }; + + ///@brief An active philosopher, philosophising and eating at the table. + class Philosopher: public Process { + ///@brief The table. + Table& table; + ///@brief The seat number of this particular philosopher. + unsigned int seat; + + public: + ///@brief Constructor initializing table and seat. + Philosopher(Simulation& sim, Table& table, unsigned int seat) + : Process(sim, "Philosopher"), + table(table), + seat(seat) + {} + + ///@brief Method containing the lifecycle of the philosopher. + int main() override { + using namespace odemx::random; + NegativeExponential thinking_duration(getSimulation(), "thinking", 1.0); + Uniform artificial_delay(getSimulation(), "delay", 0.1, 0.2); + Normal eating_duration(getSimulation(), "eating", 0.5, 0.2); + + while (true) { + double duration; + + // spend some time pondering the nature of things + holdFor(thinking_duration.sample()); + + // acquire the first fork + table.acquire_fork(seat); + + // introduce an artificial delay to leave room for deadlocks + holdFor(artificial_delay.sample()); + + // acquire the second fork + table.acquire_fork(seat + 1); + + // spend some time eating + do duration = eating_duration.sample(); + while (duration < 0.0); + holdFor(duration); + + // release the forks + table.release_fork(seat + 1); + table.release_fork(seat); + } + + return 0; + } + }; + + ///@brief A dining-philosopher-specific simulation class. + class Sim: public Simulation { + ///@brief The table. + Table table; + ///@brief A vector storing all of the philosophers. + std::vector<std::unique_ptr<Philosopher>> philo; + + public: + ///@brief Constructor populating the philosopher vector based on the + /// requested entry-count. + Sim(unsigned int count) + : Simulation("Dining Philosophers"), + table(*this, count) + { + // create the philosopher-processes + for (int i = 0; i < count; ++i) { + philo.push_back(std::make_unique<Philosopher>(*this, table, i)); + } + } + + ///@brief Runs multiple simulations in quick succession and returns + /// statistical information about the model-times recorded before a + /// deadlock occurred. + static Tally main(unsigned int count, unsigned int reruns) { + Tally sim_duration(odemx::getDefaultSimulation(), "Sim Duration"); + unsigned long seed = 907; + + // run the simulation a number of times + for (unsigned int i = 0; i < reruns; ++i) { + // create a new simulation context + Sim sim(count); + + // set the seed for the simulation's rng + sim.setSeed(seed); + + // run until no more processes can be scheduled; + // this would indicate a deadlock-situation + sim.run(); + + // tabulate the latest simulation time + sim_duration.update(sim.getTime()); + + // extract the seed for the next simulation + seed = sim.getNextSeed(); + } + + return sim_duration; + } + + protected: + ///@brief Automatically called method activating the philosophers. + void initSimulation() override { + // activate the philosopher-processes + for (auto& p: philo) { p->hold(); } + } + }; +} + +#ifdef RUST_FFI +///@brief Entry point for the benchmarking function. +extern "C" void philosophers(unsigned int count, unsigned int reruns) { + Philosophers::Sim::main(count, reruns); +} +#else +int main() { + Tally sim_duration = + Philosophers::Sim::main(PHILOSOPHER_COUNT, EXPERIMENT_COUNT); + + // generate the report + OStreamReport report(std::cout); + report.addReportProducer(sim_duration); + report.generateReport(); + return 0; +} +#endif diff --git a/odemx-lite/COPYING b/odemx-lite/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..acb9717c93b70722674b2f1aa1988732e9a3c8fa --- /dev/null +++ b/odemx-lite/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control_ compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control_ the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/odemx-lite/Doxygen/Doxyfile b/odemx-lite/Doxygen/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..820963fe3c63a54c3db3335a65fa887d4c3c239d --- /dev/null +++ b/odemx-lite/Doxygen/Doxyfile @@ -0,0 +1,2421 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = ODEMx-control + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control_ system is used. + +PROJECT_NUMBER = "Version 3.1 Humboldt-Universität zu Berlin" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = ../include + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control_ system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../src \ + ../include \ + . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.h \ + *.cpp \ + *.dox \ + *.hpp + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.svn/* \ + */omsi/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = SuiteCppLogUnitTest \ + std + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = ../examples + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control_ the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = ../doc/odemx.chm + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control_ over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = YES + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = YES + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = ../src + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = ODEMX_USE_CONTINUOUS \ + ODEMX_USE_OBSERVATION + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = NO + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = NO + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control_ over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = YES + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = YES + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = /usr/local/bin/dot + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/odemx-lite/Doxygen/Doxyfile.bak b/odemx-lite/Doxygen/Doxyfile.bak new file mode 100644 index 0000000000000000000000000000000000000000..c2f8ef626f9c9f676e10a3de8db7e13cb841c6ab --- /dev/null +++ b/odemx-lite/Doxygen/Doxyfile.bak @@ -0,0 +1,1700 @@ +# Doxyfile 1.7.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = ODEMx + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = "Version 3.0 Humboldt-Universität zu Berlin" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ${CMAKE_CURRENT_BINARY_DIR}/doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = ../include + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ${CMAKE_CURRENT_SOURCE_DIR}/Doxygen \ + ${CMAKE_CURRENT_SOURCE_DIR}/src \ + ${CMAKE_CURRENT_SOURCE_DIR}/include \ + ${CMAKE_CURRENT_SOURCE_DIR}/external/CppLog \ + ${CMAKE_CURRENT_BINARY_DIR}/include + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h \ + *.cpp \ + *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = ${CMAKE_CURRENT_SOURCE_DIR}/test + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.svn/* \ + */omsi/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = SuiteCppLogUnitTest \ + std \ + std::tr1 \ + Poco + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = ${CMAKE_CURRENT_SOURCE_DIR}/examples \ + ${CMAKE_CURRENT_SOURCE_DIR}/external/CppLog/src/samples/src + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = ../doc/odemx.chm + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [0,1..20]) +# that doxygen will group on one line in the generated HTML documentation. +# Note that a value of 0 will completely suppress the enum values from +# appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = YES + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = YES + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = ${CMAKE_CURRENT_SOURCE_DIR}/src + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = ODEMX_USE_CONTINUOUS \ + ODEMX_USE_OBSERVATION + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = ${CMAKE_CURRENT_BINARY_DIR}/doc/odemx.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = NO + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, svg, gif or svg. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/odemx-lite/Doxygen/groups.dox b/odemx-lite/Doxygen/groups.dox new file mode 100644 index 0000000000000000000000000000000000000000..c7b884ab767d5e6f87ba73ebfac3c19e4a7c3f40 --- /dev/null +++ b/odemx-lite/Doxygen/groups.dox @@ -0,0 +1,54 @@ +/** + +\defgroup base Base +The core group of ODEMx modeling classes. The module contains base classes +for discrete and continuous processes, events, a scheduler and ts execution +list, as well as the simulation context. See \ref module_base. + +\defgroup coroutine Coroutine +This group contains a portable coroutine implementation that is used to model +the sequentialized execution of logically parallel processes. The implementation +on POSIX systems used to be based on the functions \c setjmp and \c longjmp +which always replaced the runtime stack with that of the current coroutine. +On MS Windows platforms, the lightweight fibers were used. The same API has +since been implemented for POSIX platforms on top of the @c ucontext. This is +safer because it provides a separate runtime stack for each coroutine. +See \ref module_coroutine. + +\defgroup data Data +The data group contains all components tasked with producing, collecting, +printing, or storing ODEMx simulation data. There are base classes for +three data collection concepts: logging, observation, and report. +See \ref module_data. + +\defgroup protocol Protocol +This group provides model components for simulating communication +protocols in arbitrary networks. Primarily, the components are used +to assemble protocol stacks and to link nodes in a network. The behavior +of active components in the stacks is user-defined. +See \ref module_protocol. + +\defgroup random Random +This module provides random number generators for continuous and discrete +distributions. The classes offer support for a variety of distributions +such as uniform, normal, or poisson distributions. +See \ref module_random. + +\defgroup statistics Statistics +This module provides various classes for computing statistical analyses. +The classes range from simple counters to more sophisticated accumulating +components for various statistical characteristics. +See \ref module_statistics. + +\defgroup synch Synchronization +This module consists of classes which can be used for synchronizing +processes. Besides different queue variants, this also includes a waiting +concept for processes, as well as timers and resource modeling components. +See \ref module_synchronization + +\defgroup util Utilities +This module contains ODEMx utilities, such as various exceptions, a function +for computing the library path, and string conversion functions. +See \ref module_util + +*/ diff --git a/odemx-lite/Doxygen/mainPage.dox b/odemx-lite/Doxygen/mainPage.dox new file mode 100644 index 0000000000000000000000000000000000000000..77fb57d25250d7366bb5e1ab1eccc4ec8640c91a --- /dev/null +++ b/odemx-lite/Doxygen/mainPage.dox @@ -0,0 +1,97 @@ +/** + \mainpage + + \section Introduction + Welcome to ODEMx. ODEMx is a library for discrete event simulation in C++. + \ref toc "(Table of Contents)" + + ODEMx is a C++ library for process and event simulation, which + is a branch of computer simulation. As such it uses processes and + events to model real-world or fictional systems. + A process in this context is a continuous or discrete + sequence of actions which are somehow closely related to each + other, for instance they are all 'done' by one agent. The + sequence can be divided into branches, and broken off by idle + periods or synchronisation. An event on the other hand describes + only one atomic action in this context. + + \section installation Installation + There is no installation procedure for ODEMx, at least not in + this version. To use ODEMx in your projects you need to + build the library, include its header files in your project, and + finally link your object files against the compiled library. + + As ODEMx uses many modern C++ components, it must be compiled with a + GCC version higher than 4.0 because starting with that version, + GCC includes the C++ standard library extensions from the + Technical Report 1, which adds new containers such as hash maps, + tuples and arrays, as well as smart pointers and function object + generators. All of these components are currently in use in ODEMx. + + Building ODEMx on Windows operating systems requires MinGW + and MSYS to be installed. The current version of ODEMx does not + support Visual Studio because there are several known bugs in the + implementation of the TR1 components. Even though the library and + its dependencies have been successfully built with VS 2008 and + VS 2010, the resulting code did not run reliably. + + \subsection mingw_setup Setting up MinGW and MSYS + The procedure is fairly simple, as it only requires downloading + the minimal MinGW component set, plus the g++ compiler + (see http://mingw.org/wiki/Getting_Started). All of the downloaded + archives are simply unzipped to the same directory of the user's choice. + After that, the MinGW/bin path needs to be added to the Windows PATH + variable, and then gcc should be available from the command line. + MSYS provides a collection of GNU utilities such as bash, make and rm. + ODEMx itself does not require this, but the POCO libraries' + build system for MinGW depends on the execution of various + build scripts, besides make. MSYS can be set up by getting the + installer for version 1.0.11 (http://downloads.sourceforge.net/mingw/MSYS-1.0.11.exe) + + \section firststeps First Steps + At first you will have to build ODEMx - see \ref installation for details. + Afterwards try the examples included. That should give you a good start. + Apart from that you can use them to check whether ODEMx is working properly on your + computer. \n + + ODEMx includes an online documentation as well. You will need Doxygen + (http://www.doxygen.org) to generate the documentation from the source files. + To do so, change to \c odemx/Doxygen directory and run \c doxygen. + + \section contributions Contributions + ODEMx is based on ODEM (http://odem.sf.net). That's why all contributors of + ODEM could be listed here, too. Instead only those who put their + hands on this code directly will be mentioned. Anyway, we encourage + you to take a look at ODEM and its contributors list as well. + + \li Ralf Gerstenberger <gerstenb@users.sourceforge.net> + \li Ronald Kluth (since Version 2.0) + \li Toralf Niebuhr <niebuhr@niebuhrt.de> (since Version 2.0) + \li Magnus Mueller <evnu@users.sf.net> (since Version 3.0) + + \section toc Table of Contents + <ol> + <li>\ref overview + <ol> + <li>\ref module_base</li> + <li>\ref module_coroutine</li> + <li>\ref module_data</li> + <li>\ref module_protocol</li> + <li>\ref module_random</li> + <li>\ref module_statistics</li> + <li>\ref module_synchronization</li> + <li>\ref module_test</li> + <li>\ref module_util</li> + </ol> + </li> + <li>\ref otoo + </li> + </ol> + + \section copyright Copyright and License + ODEMx is protected by the GNU LESSER GENERAL PUBLIC LICENSE as + described in the file COPYING, which has to be present in + the ODEMx package; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +*/ diff --git a/odemx-lite/Doxygen/namespaceOdemx.dox b/odemx-lite/Doxygen/namespaceOdemx.dox new file mode 100644 index 0000000000000000000000000000000000000000..b3dc8581ca14af8f1dd3eed8f46699cc3973b7d0 --- /dev/null +++ b/odemx-lite/Doxygen/namespaceOdemx.dox @@ -0,0 +1,13 @@ +/** \namespace odemx + + \brief Main namespace for this project. + + <!-- [detailed description] --> + All classes and types are members of this namespace. + + <!-- [\todo {todos for this file}]* --> + \todo spell checking of comments and documentation + \todo finish documentation + + \since 1.0 +*/ diff --git a/odemx-lite/Doxygen/odemToOdemx.dox b/odemx-lite/Doxygen/odemToOdemx.dox new file mode 100644 index 0000000000000000000000000000000000000000..471d6f24b17de0f14a14344cd2427c1e43c10b90 --- /dev/null +++ b/odemx-lite/Doxygen/odemToOdemx.dox @@ -0,0 +1,691 @@ +/** +\page otoo From ODEM to ODEMx +In this chapter we describe differences between +ODEMx and its predecessor ODEM and features they have in common. \n + +<ol> +<li>\ref oview +</li> +<li>\ref nfeatures +</li> +<li>\ref lfeatures +</li> +<li>\ref changes +</li> +</ol> + +\section oview Overview +The following table lists all classes from ODEM and ODEMx and +their status in ODEMx. This Table is not supposed to be +a documentation for ODEMx. \n + +<table> +<tr> +<td><b>Class</b></td><td><b>Status</b></td> +<td><b>Description</b></td><td><b>Comment</b></td> +</tr> + +<tr> +<td>Accumulate</td> <td>changed</td> <td>Statistics</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>Bin</td> <td>changed</td> <td>Ressource-like synchronisation</td> <td>\ref synchi1</td> +</tr> + +<tr> +<td>BinObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>Buff_head</td> <td>lost</td> <td>Buffered communication</td> <td>not transferred to ODEMx</td> +</tr> + +<tr> +<td>Buff_tab</td> <td>lost</td> <td>Buffered communication</td> <td>not transferred to ODEMx</td> +</tr> + +<tr> +<td>Buff_tail</td> <td>lost</td> <td>Buffered communication</td> <td>not transferred to ODEMx</td> +</tr> + +<tr> +<td>CondQ</td> <td>changed</td> <td>Condition queue</td> <td>\ref synchi1</td> +</tr> + +<tr> +<td>CondQObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>Continuous</td> <td>changed</td> <td>Time-continuous process</td> <td>\ref continu1</td> +</tr> + +<tr> +<td>ContinuousObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>ContuTrace</td> <td>new</td> <td>Trace for Continuous</td> <td>\ref continu1</td> +</tr> + +<tr> +<td>Coroutine</td> <td>new</td> <td>Portable coroutine implementation</td> <td>\ref corout1</td> +</tr> + +<tr> +<td>CoroutineContext</td> <td>new</td> <td>Portable coroutine implementation</td> <td>\ref corout1</td> +</tr> + +<tr> +<td>CoroutineContextObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>CoroutineObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>Count</td> <td>changed</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>DebugTrace</td> <td>lost</td> <td>Text-logfile</td> <td>replaced by HtmlTrace</td> +</tr> + +<tr> +<td>DefaultContext</td> <td>new</td> <td>Portable coroutine implementation</td> <td>\ref corout1</td> +</tr> + +<tr> +<td>DefaultOrder</td> <td>new</td> <td>Process sorting scheme</td> <td>\ref proque1</td> +</tr> + +<tr> +<td>DefaultSimulation</td> <td>new</td> <td>Default implementation of Simulation</td> <td>\ref encaps1</td> +</tr> + +<tr> +<td>DefaultTimeIO</td> <td>lost</td> <td>Time to string to time</td> <td>not transferred</td> +</tr> + +<tr> +<td>DefLabeledObject</td> <td>new</td> <td>Object labels</td> <td>\ref label1</td> +</tr> + +<tr> +<td>Discrete</td> <td>lost</td> <td>Time-discrete process</td> <td>replaced by Process</td> +</tr> + +<tr> +<td>Dist</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>DistContext</td> <td>new</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Draw</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>dynTableDefinition</td> <td>new</td> <td>Report</td> <td>\ref report1</td> +</tr> + +<tr> +<td>Elem</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Empirical</td> <td>lost</td> <td>Random number generator</td> <td>not transferred</td> +</tr> + +<tr> +<td>Entity</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Entry</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Erlang</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Event</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>ExecutionList</td> <td>new</td> <td>Process scheduling</td> <td>\ref proce2</td> +</tr> + +<tr> +<td>ExecutionListObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>File_list</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>FormatedTimeInput</td> <td>lost</td> <td>String to time</td> <td>not transferred</td> +</tr> + +<tr> +<td>FormatedTimeOutput</td> <td>lost</td> <td>Time to string</td> <td>not transferred</td> +</tr> + +<tr> +<td>Graph</td> <td>lost</td> <td>ODEM trace for Continuous</td> <td>not transferred</td> +</tr> + +<tr> +<td>Head</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Histo</td> <td>changed</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>HtmlReport</td> <td>new</td> <td>Report</td> <td>\ref report1</td> +</tr> + +<tr> +<td>HtmlTrace</td> <td>new</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>Iconst</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Idist</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>LabeledObject</td> <td>new</td> <td>Object labels</td> <td>\ref label1</td> +</tr> + +<tr> +<td>LabelScope</td> <td>new</td> <td>Unique object labels</td> <td>label1</td> +</tr> + +<tr> +<td>Link</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>MarkType</td> <td>new</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>Memo</td> <td>lost</td> <td>ODEM object linking</td> <td>replaced by \ref observat1</td> +</tr> + +<tr> +<td>Msg</td> <td>lost</td> <td>Buffered communication</td> <td>not transferred</td> +</tr> + +<tr> +<td>Negexp</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Normal</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>NoQueue</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>NoTally</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Observable</td> <td>new</td> <td>Observation of individual objects</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>Object_names</td> <td>lost</td> <td>Object labels</td> <td>replaced by LabeledObject</td> +</tr> + +<tr> +<td>Odem</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Poisson</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Port</td> <td>lost</td> <td>Port synchronisation</td> <td>not transferred</td> +</tr> + +<tr> +<td>Port_head</td> <td>lost</td> <td>Port synchronisation</td> <td>not transferred</td> +</tr> + +<tr> +<td>Port_tail</td> <td>lost</td> <td>Port synchronisation</td> <td>not transferred</td> +</tr> + +<tr> +<td>PriorityOrder</td> <td>new</td> <td>Process sorting scheme</td> <td>\ref proque1</td> +</tr> + +<tr> +<td>Process</td> <td>changed</td> <td>Process</td> <td>\ref proce2</td> +</tr> + +<tr> +<td>Process_clock</td> <td>lost</td> <td>Time event</td> <td>not transferred</td> +</tr> + +<tr> +<td>ProcessObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>ProcessOrder</td> <td>new</td> <td>Process sorting scheme</td> <td>\ref proque1</td> +</tr> + +<tr> +<td>ProcessQueue</td> <td>new</td> <td>Process list</td> <td>\ref proque1</td> +</tr> + +<tr> +<td>Queue</td> <td>changed</td> <td>Process synchronisation queue</td> <td>\ref synchi1</td> +</tr> + +<tr> +<td>Randint</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Rconst</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Rdist</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>Regression</td> <td>changed</td> <td>Statistics</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>Report</td> <td>new</td> <td>Report</td> <td>\ref report1</td> +</tr> + +<tr> +<td>ReportProducer</td> <td>new</td> <td>Report</td> <td>\ref report1</td> +</tr> + +<tr> +<td>Reportq</td> <td>changed</td> <td>Report</td> <td>replaced by Report</td> +</tr> + +<tr> +<td>Res</td> <td>changed</td> <td>Ressource-like synchronisation</td> <td>\ref synchi1</td> +</tr> + +<tr> +<td>ResObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>Resource</td> <td>lost</td> <td>Ressource-like synchronisation</td> <td>not transferred</td> +</tr> + +<tr> +<td>Sched</td> <td>lost</td> <td>Scheduling</td> <td>replaced by ExecutionList</td> +</tr> + +<tr> +<td>ShortGermanTF1</td> <td>lost</td> <td>Time to string</td> <td>not transferred</td> +</tr> + +<tr> +<td>Simulation</td> <td>new</td> <td>Simulation</td> <td>\ref encaps1</td> +</tr> + +<tr> +<td>SimulationObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> + +<tr> +<td>Stackdir</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>Starter</td> <td>lost</td> <td>ODEM-internal</td> <td>not transferred</td> +</tr> + +<tr> +<td>StatisticManager</td> <td>new</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>StatisticObject</td> <td>new</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>Sum</td> <td>changed</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>Tab</td> <td>changed</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>Table</td> <td>new</td> <td>Report data table</td> <td>\ref report1</td> +</tr> + +<tr> +<td>TableDefinition</td> <td>new</td> <td>Report table structure</td> <td>\ref report1</td> +</tr> + +<tr> +<td>Tag</td> <td>new</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>Tally</td> <td>changed</td> <td>Statistic</td> <td>\ref stati1</td> +</tr> + +<tr> +<td>Timer</td> <td>lost</td> <td>Time events</td> <td>not transferred</td> +</tr> + +<tr> +<td>Trace</td> <td>changed</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>TraceClient</td> <td>lost</td> <td>Trace</td> <td>replaced by TraceConsumer</td> +</tr> + +<tr> +<td>TraceConsumer</td> <td>new</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>TraceFilter</td> <td>new</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>TraceProducer</td> <td>new</td> <td>Trace</td> <td>\ref trace1</td> +</tr> + +<tr> +<td>TraceServer</td> <td>lost</td> <td>Trace</td> <td>replaced by Trace</td> +</tr> + +<tr> +<td>TypedObject</td> <td>new</td> <td>C++ RTTI</td> <td>Interface to standard C++ RTTI</td> +</tr> + +<tr> +<td>Unifrom</td> <td>changed</td> <td>Random number generator</td> <td>\ref randi1</td> +</tr> + +<tr> +<td>utTableDef</td> <td>new</td> <td>Report</td> <td>\ref report1</td> +</tr> + +<tr> +<td>Version</td> <td>new</td> <td>ODEMx version information</td> <td>no comment</td> +</tr> + +<tr> +<td>Wait</td> <td>new</td> <td>Synchronization with child-processes</td> <td>\ref synchi1</td> +</tr> + +<tr> +<td>WaitQ</td> <td>changed</td> <td>Master-Slave synchronisation</td> <td>\ref synchi1</td> +</tr> + +<tr> +<td>WaitQObserver</td> <td>new</td> <td>Observer</td> <td>\ref observat1</td> +</tr> +</tr> + +</table> + + +\section nfeatures New features +\subsection observat1 Observation +ODEMx introduces a system for observing individual objects. Observable +objects provide an interface with call-back-functions for the events of that +object. Observers implement this interface to handle selected events. An +observable object inherits an observer management from the template class Observable. Observable objects also have an optional +constructor parameter, which allows to register an initial observer. +\par Documentation: +\li \ref odemx::data::Observable +\li \ref odemx::base::ProcessObserver + +\subsection encaps1 Encapsulation +In contrast to ODEM, ODEMx does encapsulate simulations. While in ODEM the main +program is always made a part of the simulation, ODEMx separates the simulation +from its environment. Simulation specific data and services are put into +the class Simulation instead of being placed in the global scope. For many objects +of ODEMx this requires a link to the Simulation class, which is in general +handed over during construction. \n +The separation is often realised by the introduction of context-objects. +Simulation for instance is the context-object for processes. Due to multiple +inheritance Simulation also serves as a context-object for other types of +objects, like random number generators, labelled objects and trace producers. \n +The advantage of the encapsulation is that a simulation can be programmed +as an independent component without side-effects on its environment. It is +for instance possible to run a simulation in a simulation. +\par Documentation: +\li \ref odemx::base::Simulation +\li \ref odemx::base::Process + +\subsection corout1 Coroutines +ODEMx separates the implementation of coroutines from the implementation of +processes for process-simulation. ODEM on the other hand implements the +coroutine functionality inside its process implementation. The coroutine +implementation of ODEMx is apart from a few concepts in the Utilities module +independent from the rest of ODEMx. It is designed to be portable and already +ported to Windows higher than Windows 95 (x86 architecture) as well as Unix and +Linux (Sparc, and x86 architecture). Though in some compiler-os-platform +configurations there could be problems. \n +The techniques used to realise coroutines are based on ODEM which in turn has +used previous works from HANSEN and others. ODEMx however introduces the +encapsulation of coroutines in separate contexts. + +\subsection proque1 Process queue +While in ODEM processes are itself designed to be part of a linked list, ODEMx +uses STL containers to manage object collections. ProcessQueue is introduced +in ODEMx to manage such collections. ProcessQueue allows different sorting +schemes like considering the priority or the execution time of a process. +Derived from ProcessQueue is the class Queue designed for synchronisation +objects like Res, Bin, and WaitQ. + + +\section lfeatures Lost features +\subsection memo1 Memo +In ODEM many classes include the functionality to be part of a linked list. +The Memo concept of ODEM uses this property to provide a synchronisation +technique. A Process object can genericWait in a Memo object until the Memo object +is alerted or becomes 'available'. From Memo derived classes can override +a function to redefine the 'available' condition. Process from ODEM for +instance is also a Memo object which redefines 'available'. A Process in +ODEM is 'available' if it is terminated. \n +ODEMx does not include the Memo +feature. But it is possible to realise Memo-like synchronisation with the +\ref observat1 feature. The ODEMx class Wait in the module Synchronisation is +an example for this. + +\subsection port1 Port +In the HU-Release of ODEMx there is no concept for a buffered process-communication. +A user will have to develop its own classes for this purpose. ODEM had such +a concept in its Port mechanism. + +\subsection timioq Time translation +In the later versions of ODEM a simtime to string to simtime translation +was introduced to allow human readable time strings other than simple +floating point numbers. This feature was introduced for a special application +of ODEM. ODEMx has not yet such a feature, but is likely to get it in +a future version. + +\subsection gl1 OpenGL visualisation +ODEM had an experimental 3D visualisation of simulation events. Experiences +from this 3D-project had lead to changes in the trace-mechanism which finally +concluded the current Trace concept of ODEMx. A visualisation might be +available in ODEMx in a future version. But the old 3D-Trace of ODEM is not +transferable without a redesign. + +\subsection graph1 Continuous Graph +ODEM provides the class Graph which logs Continuous state changes in a text +format used by external visualisation tools. A similar tool is already +present in ODEMx (\ref odemx::base::ContuTrace). But at the moment there is no +component in ODEMx that generates output in the exact text-format like Graph. + +\subsection buffer1 Buffer +Like the missing \ref port1 mechanism the simplified Buffer system is not +transferred to ODEMx. + +\subsection empiri1 Empirical +Empirical from ODEM is not available in ODEMx. + + +\section changes Changes +\subsection synchi1 Synchronisation +ODEMx provides the following synchronisation components: \ref odemx::synchronization::Res, +\ref odemx::synchronization::Bin, \ref odemx::synchronization::WaitQ, \ref +odemx::synchronization::CondQ and +\ref odemx::synchronization::Wait. +The first four components are transferred from ODEM but are changed. +Res and Bin for instance are not derived from a common base class Resource. +The constructors of both classes have additional parameters compared to +Res and Bin from ODEM which reflect the \ref encaps1 and the \ref observat1 +feature. Both classes have more get* methods to receive information about +the statistic. Both classes have a report function according to the \ref report1 +changes. The basic synchronisation functions however are not changed. \n +Similar things can be said about WaitQ and CondQ. The general meaning has not +changed while the classes have been adjusted to reflect the ODEMx features. +In WaitQ and CondQ however, small changes have been applied to the classic +synchronisation functions as well. +\par Documentation: +\li \ref odemx::synchronization::Res +\li \ref odemx::synchronization::Bin +\li \ref odemx::synchronization::WaitQ +\li \ref odemx::synchronization::CondQ + +\subsection stati1 Statistics +Many of the statistic components from ODEM have been transferred to ODEMx. +The components in ODEMx share the update() function with their predecessors +as well as the used algorithms. They +were also changed to match the \ref encaps1 and the \ref report1 +feature. Furthermore, several get* methods for +the statistical data were added. +\par Documentation: +\li \ref odemx::statistics::Accumulate +\li \ref odemx::statistics::Count +\li \ref odemx::statistics::Histogram +\li \ref odemx::statistics::Regression +\li \ref odemx::statistics::Sum +\li \ref odemx::statistics::Tally + +\subsection randi1 Random +The random number generators in ODEMx were taken from ODEM and changed +to match the features of ODEMx. They have additional get* methods for +statistical information, and require a pointer to a DistContext +object during construction. They also provide a report function for the +report feature of ODEMx. \n +The DistContext class was introduced to support the \ref encaps1 feature. +All random number generators linked to one DistContext are +independent from each other, while the RNGs in different DistContext +produce the same sequence of numbers (unless the seed is changed). +\par Documentation: +\li \ref odemx::statistics::Accumulate +\li \ref odemx::statistics::Count +\li \ref odemx::statistics::Histogram +\li \ref odemx::statistics::Regression +\li \ref odemx::statistics::Sum +\li \ref odemx::statistics::Tally + +\subsection proce2 Process +The Process class of ODEMx replaces the Process class and the Discrete +class of ODEM. Its interface is more like the interface of Discrete +than of Process. The following table matches the different scheduling +functions of Discrete to the functions of ODEMx Process: \n + +<table> +<tr><td><b>Discrete</b></td> <td><b>odemx::base::Process</b></td></tr> +<tr><td>start(NOW)</td> <td>hold()</td></tr> +<tr><td>start(AT, t)</td> <td>holdUntil(t)</td></tr> +<tr><td>start(AT, t, PRIOR)</td> <td>activateAt(t)</td></tr> +<tr><td>start(DELAY, t)</td> <td>holdFor(t)</td></tr> +<tr><td>start(DELAY, t, PRIOR)</td> <td>activateIn(t)</td></tr> +<tr><td>activate(NOW)</td> <td>hold() or activate() (FIFO or LIFO)</td></tr> +<tr><td>activate(AT, t)</td> <td>holdUntil(t)</td></tr> +<tr><td>activate(AT, t, PRIOR)</td> <td>activateAt(t)</td></tr> +<tr><td>activate(DELAY, t)</td> <td>holdFor(t)</td></tr> +<tr><td>activate(DELAY, t, PRIOR)</td> <td>activateIn(t)</td></tr> +<tr><td>activate(BEFORE, q)</td> <td>activateBefore(q)</td></tr> +<tr><td>activate(AFTER, q)</td> <td>activateAfter(q)</td></tr> +<tr><td>hold(t)</td> <td>holdFor(t)</td></tr> +<tr><td>passivate()</td> <td>sleep()</td></tr> +<tr><td>e_interrupt()</td> <td>interrupt() (!see documentation!)</td></tr> +<tr><td>cancel()</td> <td>cancel()</td></tr> +</table> \n +ODEMx Process has only one priority attribute which is used in scheduling +as well as in synchronisation queues. The \c interrupt function in ODEMx has +a different effect than the \c e_interrupt of Discrete. In ODEMx an interrupt +causes an immediate activation (activate). The interrupted process is +responsible to handle the interrupt. +\par Documentation: +\li \ref odemx::base::Process + +\subsection continu1 Continuous +The Continuous class of ODEMx is derived from Process. The algorithm used +to compute the state changes is taken from ODEM. Some of the Continuous +functions in ODEM are also transferred to ODEMx. Other than the ODEM version +of Continuous, the ODEMx version does not log the state changes on its own. +If a user wants this service he/she has to use the ODEMx class ContuTrace. +\par Documentation: +\li \ref odemx::base::Continuous +\li \ref odemx::base::ContuTrace + +\subsection label1 Object labels +The support of object labels has changed in ODEMx. It is now provided +by the classes \ref odemx::LabeledObject, \ref odemx::LabelScope and +\ref odemx::DefLabeledObject. In contrast to ODEM labels are no longer +unique to the program but to a certain LabelScope. Each simulation has +of course its own scope. +\par Documentation: +\li \ref odemx::LabeledObject +\li \ref odemx::LabelScope +\li \ref odemx::DefLabeledObject + +\subsection trace1 Trace +\warning +The current implementation (as of Mi 16. Mär 15:54:28 CET 2011) differs from + the following description. An example on the default trace functionality is given in Example_Shop.cpp + + +\p +ODEMx introduces the class HtmlTrace. Objects of this class generate Html +output from simulation events. HtmlTrace also provides a simple filter +for events to reduce the generated output. The trace control_ is implemented +in the ODEMx Trace class which is a base class of Simulation. +\par Documentation: +\li \ref odemx::HtmlTrace + +\subsection report1 Report +ODEMx supports several reports in one simulation. A report is generated by +an object of the HtmlReport class. In contrast to ODEM a user has to register +model components to the report. The final report is triggered manually by the function call +'generateReport()'. +\par Documentation: +\li \ref odemx::HtmlReport + + +*/ diff --git a/odemx-lite/Doxygen/odemxOverview.dox b/odemx-lite/Doxygen/odemxOverview.dox new file mode 100644 index 0000000000000000000000000000000000000000..e5c47c9fd7dc5b716fb0ccce53c084fa7bbe0d12 --- /dev/null +++ b/odemx-lite/Doxygen/odemxOverview.dox @@ -0,0 +1,262 @@ +/** + +\page overview ODEMx - An Overview of the Library. + +This page describes the following topics: +<ul> + <li>\ref structure</li> + <li>\ref module_base</li> + <li>\ref module_coroutine</li> + <li>\ref module_data</li> + <li>\ref module_protocol</li> + <li>\ref module_random</li> + <li>\ref module_statistics</li> + <li>\ref module_synchronization</li> + <li>\ref module_test</li> + <li>\ref module_util</li> +</ul> + +\section structure Library Structure +On this page we give an overview of the structure of ODEMx and its primary +simulation components. +ODEMx is divided into the modules \ref base, \ref coroutine, \ref data, +\ref protocol, \ref random, \ref statistics, \ref synch, \b Test, +and \ref util. All modules depend on the modules Data and Utilities. +The following sections describe the concepts implemented by each module. + +\section module_base Base Components +The \ref base module contains the core of the simulation building blocks, such +as the simulation context (including a default implementation), base classes +for events and processes, as well as the scheduler with its execution list. +Besides time-discrete processes, ODEMx also provides support for time-continuous +processes on the basis of ordinary differential equations. + +Every simulation with ODEMx requires an implementation of the abstract base +class odemx::base::Simulation. This class provides a context for all the +other model components like processes, events, synchronization classes, +and random number generators. In user-defined simulation classes the method +@c initSimulation must be implemented in order to create and initialize model +components. + +For convenience ODEMx also provides the class \c DefaultSimulation with an empty +implementation of @c initSimulation. If the user does not want to define a +specific simulation class, this default implementation can be used. A reference +to a static object of this class is returned by the free function +odemx::getDefaultSimulation. However, this requires that all simulation +components are initialized globally, or from within the @c main function of the +simulation program. ODEMx allows at most one DefaultSimulation-object per program. +If users define their own simulation classes, several simulation contexts can +be used within the same program. This includes simulations inside +of simulations as well as the parallel (interleaved) execution of simulations. + +The base class for all simple simulations events is odemx::base::Event. +Events typically describe exactly one action that happens during the +simulation run. Each different event type must be implemented as a +specialization of this class, which usually only requires the definition +of the method \c eventAction. Events may reschedule themselves in order to +model recurring atomic actions in a system. + +The class odemx::base::Process serves as base class for all user-defined classes modeling +discrete processes. Each different type of process in a system model requires +the specification of a new process class. This class has to define the behavior +(the sequence of actions, synchronizations and idle periods) of its objects as +an implementation of the method @c main. +While process classes are not necessarily associated with specific simulation +classes, every process object must be linked to only one simulation context. +Thus, the constructor of class Process requires a reference to a simulation +object. + +The class odemx::base::Continuous is the base class +for continuous processes. Continuous itself is derived from Process, but +provides additional functions to define time-continuous behavior. This kind +of behavior can only be approximated by ODEMx by using a stepwise computation +of state changes, which of course introduces an inherent error rate. +ODEMx is observing these error values to stay within defined boundaries. +In addition to its implementation of @c main, user-defined time-continuous processes +must also provide an implementation of the method @c derivatives. In this +method the continuous state changes are coded by setting the change rates +for each state variable. A continuous computation phase is started in @c main +by calling the method @c integrate (which internally uses @c derivatives). +The output of continuous processes can be recorded by an object of type +odemx::base::ContuTrace, which observes valid state changes and logs the +computed values of each valid step to a text file. An object of type ContuTrace +is always linked to exactly one object of type Continuous. + +\section module_coroutine Coroutine Implementation +The module \ref coroutine provides a platform-independent implementation of +coroutines, which are essentially functions whose execution can be stopped and +resumed at predefined points. This mechanism allows the modeling of +pseudo-parallel function execution through coroutine switches, thereby +changing the execution context between several different coroutines in a +sequentialized and deterministic manner. This concept is used for modeling +ODEMx processes, whose logically parallel execution must be sequentialized, by +implementing their lifetime and behavior on the basis of coroutines. The +difference to threads is that coroutines are generally lighter constructs than +threads, and that their execution order is always deterministic and reproducible. + +The class odemx::coroutine::Coroutine is based on the Windows Fiber API. On POSIX +platforms, the functionality of fibers is emulated and implemented on top of the +user context and its related functions, which also allows context switching in +a deterministic manner. This implementation assigns each coroutine its own +runtime stack, which may consume a lot of memory when simulations contain many +processes. Therefore, ODEMx also +retains support for the legacy implementation of coroutines, which is based +on copying and replacing only the relevant part of the program's runtime stack +using the functions +@c setjmp and @c longjmp. While this method offers the advantage of a smaller +memory footprint, it has the drawback that processes cannot exchange addresses +of stack-allocated objects because these are simply not available at the +expected address after a context switch. + +\section module_data Data Collection, Storage, and Display +Module \ref data combines all classes that deal with the computation, collection, +storage, and display of simulation data. Three different concepts +are employed for the collection of simulation data: +@li Logging +@li Report +@li Observation. + +@b Logging is provided by the external library CppLog. This concept is employed +to collect detailed data about state changes in the system model. Logging +components play one of three roles: source, channel, and sink. +Channels represent different logging +categories such as trace, debug, or statistics. ODEMx data sources are represented +by the class odemx::data::Producer, which is used as base class for nearly all +ODEMx model elements. Logging sinks are classes that implement a record-consumer +interface. ODEMx provides sinks that write simple text or XML, and it can also +store records in a database. Supported database management systems (DBMS) are +SQLite, which is embedded in ODEMx, and external DBMSs, which support access +via ODBC. + +@b Report is a concept that allows the display of accumulated data in tables. +Report-producing classes implement the interface odemx::data::ReportProducer +to be accessed upon report +generation (either simple text or XML format). Currently, the report concept +is used by statistics-computing classes only. These components collect their +data internally and compute statistical characteristics. All relevant information +such as component name, parameters, reset time, and the computed values is fed +to predefined tables, which are then arranged for display by an implementation +of the base class odemx::data::Report. + +@b Observation is a concept that focuses on the observation of the state +changes of specific objects. +There are two roles: observer and observable. One observable object may have +multiple observers. Observable classes must be derived from the class template +odemx::data::Observable and additionally provide an @c Observer interface, +which must be implemented by specific observer classes in order to be able +to receive notifications. When certain state changes occur, all registered +observers of an observable object are notified via calls to the interface. + +\section module_protocol Communication Protocol Simulation +The module \ref protocol contains higher level modeling classes for simulating +communication networks. Conceptually, networks are modeled as collections of +interconnected nodes, each of which owns one or more network interfaces for +communicating with connected peers. There is no base class for nodes, as these +can be of arbitrary structure. ODEMx merely requires that one or several +transmission media manage a network topology of registered network interfaces. +Links between these interfaces are set via the method @c Medium::addLink. It +is also possible to dynamically remove links during a simulation run. +For convenience, simple communication services can also be realized without +specifying a network topology. In this case, each network node only needs +to use its own Service object (derived from class odemx::protocol::Service), +which implements the network topology as direct connections between all +registered nodes. + +More advanced communication models usually employ a protocol stack (as +provided by the class odemx::protocol::Stack), which is typically comprised +of several protocol layers, each offering one or several different protocol +services. Access to services is provided through asynchronous interfaces, +so-called service access points (SAP, modeled by class odemx::protocol::Sap). +The service functionality is always implemented by subclasses of +odemx::protocol::ServiceProvider. This base class is the foundation for more +specific implementations such as Service, Entity, and Device. Service +providers are the active components in protocol simulations and are therefore +derived from class Process. Their behavior is implemented as waiting period for +input on one of their SAPs. Users must define what is to be done when one +of these input queues contains data. + +When using a stack as communication interface of network nodes, it is +possible to create simulation models that include the physical layer. This +requires the definition of network interfaces by subclassing +odemx::protocol::Device, and the use of one or several transmission media +representing cables or radio waves. However, it is also possible to abstract +from the network topology by simply using a Service implementation in the +lowest layer of the stack. Transmission errors can be modeled by implementing +the interface odemx::protocol::ErrorModel. Instances of such classes can then +be registered globally with Service implementations or a Medium object. In the +latter case, it is also possible to assign each link between two nodes its own +error model. + +\section module_random Random Number Generation +The \ref random module is a collection of random number generators (RNGs), +which can be used for statistical simulations. Various discrete and continuous +distributions can be generated by these classes. Examples are Poisson, uniform, +or negative exponential distribution. All RNGs provide a method @c sample, +which returns the next random number. The parameters for each generator are set +in the constructor. + +\section module_statistics Statistics Computation +Module \ref statistics contains classes for statistical analyses. The provided +components are able to compute various statistical characteristics such as +min, max, mean and the standard deviation. There are also classes for creating +histograms and linear correlation analyses. + +\section module_synchronization Process Synchronization +An important part of process simulations is the synchronization of different +processes with certain situations during a simulation. The module +\ref synchronization is a collection of classes which implement +model components for various synchronization tasks. + +There are two resource-type classes: odemx::sync::Bin and odemx::sync::Res. +Both classes are used to model resource-like synchronization. A process is +blocked if the resource is exhausted. Otherwise it continous its actions by +acquiring resources. Bin and Res use token counters to simulate real resources. +There are also template-implementations of these classes, which use actual +token objects of the type provided as template argument. + +Furthermore, the classes odemx::sync::WaitQ and odemx::sync::CondQ provide +queue-like synchronisation components. The WaitQ provides a +master-slave-synchronisation (MSS). MSS is a synchronisation between two +processes. One of them (the master) takes control_ of the other (the slave) +after a successful synchronization. The slave is delivered to the master +according to different schemes. It can simply be the first process in the +waiting queue, but it can also be chosen according to the criteria of a +selection function, or a weight function provided by the queued master. +An odemx::sync::CondQ is used to wait for an arbitrary condition. A process +provides a function which implements the condition check. The condition is +checked every time any process object signals a CondQ object. The user is +responsible to call @c signal on a CondQ when the relevant situation changes +occur in the system model. + +Additionally, the synchronization module contains classes for the implementation of +a wait-alert concept. The concept's core component is the interface @c IMemory, +which is intended to store pointers to waiting processes in order to alert them +at a later point in simulation time. To use the concept, processes call the +method @c genericWait with a number of IMemory objects. As soon as one of them becomes +available and calls @c alert, the process is rescheduled for immediate +execution. As soon as it continues its execution, the process can check its +alerter and determine the appropriate action. There are several IMemory +implementations available. The default implementation is the class Memory, +which provides the storage of Process pointers and the means to alert waiting +processes. Other classes are odemx::sync::Timer, which uses a Memory member +to implement its functionality, and the class templates PortHeadT and PortTailT, +which subclass Memory to use its functionality. The latter port construct models +a limited buffer with separate input(tail) and output(head) interfaces. + +Finally, the class Wait is an observer example implementation that synchronizes +a process with a set of partner processes. The process that creates the Wait +object is blocked until one or all of its partner processes are terminated. + +\section module_test Unit Tests +The test module contains unit tests for all ODEMx components. To allow for +quick and easy test suite creation and execution of all tests, the external +library UnitTest++ is used. It has been integrated in ODEMx and provides +an easy-to-use interface for the creation of new test cases and test suites. +The test module contains its own documentation in odemx/test/Doc. + +\section module_util Utilities +This module contains utility classes and functions to simplify the implementation +of other ODEMx components. This involves memory mangement, string conversions, +and sorting. These components are usually not used directly. + +*/ diff --git a/odemx-lite/Makefile b/odemx-lite/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1b167d3d991fde2cd4a6ba53671c8baa6f141b0b --- /dev/null +++ b/odemx-lite/Makefile @@ -0,0 +1,104 @@ +OBJS = \ +./src/base/Comparators.o \ +./src/base/Continuous.o \ +./src/base/DefaultSimulation.o \ +./src/base/Event.o \ +./src/base/ExecutionList.o \ +./src/base/Process.o \ +./src/base/Sched.o \ +./src/base/Scheduler.o \ +./src/base/Simulation.o \ +./src/base/continuous/Continuous.o \ +./src/base/continuous/DfDt.o \ +./src/base/continuous/JacobiMatrix.o \ +./src/base/continuous/Monitor.o \ +./src/base/continuous/ODEObject.o \ +./src/base/continuous/ODESolver.o \ +./src/base/continuous/Rate.o \ +./src/base/continuous/State.o \ +./src/base/continuous/StateEvent.o \ +./src/base/continuous/VariableContainer.o \ +./src/base/control/ControlBase.o \ +./src/coroutine/Coroutine.o \ +./src/coroutine/CoroutineContext.o \ +./src/coroutine/ucFiber.o \ +./src/data/buffer/SimRecordBuffer.o \ +./src/data/buffer/StatisticsBuffer.o \ +./src/data/LoggingManager.o \ +./src/data/ManagedChannels.o \ +./src/data/output/ErrorWriter.o \ +./src/data/output/GermanTime.o \ +./src/data/output/Iso8601Time.o \ +./src/data/output/OStreamReport.o \ +./src/data/output/OStreamWriter.o \ +./src/data/output/TimeFormat.o \ +./src/data/Producer.o \ +./src/data/Report.o \ +./src/data/ReportProducer.o \ +./src/data/ReportTable.o \ +./src/data/SimRecord.o \ +./src/data/SimRecordFilter.o \ +./src/protocol/Device.o \ +./src/protocol/Entity.o \ +./src/protocol/ErrorModelDraw.o \ +./src/protocol/Layer.o \ +./src/protocol/Medium.o \ +./src/protocol/Sap.o \ +./src/protocol/Service.o \ +./src/protocol/ServiceProvider.o \ +./src/protocol/Stack.o \ +./src/random/ContinuousConst.o \ +./src/random/ContinuousDist.o \ +./src/random/DiscreteConst.o \ +./src/random/DiscreteDist.o \ +./src/random/Dist.o \ +./src/random/DistContext.o \ +./src/random/Draw.o \ +./src/random/Erlang.o \ +./src/random/NegativeExponential.o \ +./src/random/Normal.o \ +./src/random/Poisson.o \ +./src/random/RandomInt.o \ +./src/random/Uniform.o \ +./src/statistics/Accumulate.o \ +./src/statistics/Count.o \ +./src/statistics/Histogram.o \ +./src/statistics/Regression.o \ +./src/statistics/Sum.o \ +./src/statistics/Tab.o \ +./src/statistics/Tally.o \ +./src/synchronization/Bin.o \ +./src/synchronization/CondQ.o \ +./src/synchronization/IMemory.o \ +./src/synchronization/Memory.o \ +./src/synchronization/ProcessQueue.o \ +./src/synchronization/Queue.o \ +./src/synchronization/Res.o \ +./src/synchronization/Timer.o \ +./src/synchronization/Wait.o \ +./src/synchronization/WaitQ.o + +ifeq ($(OS),Windows_NT) + EXT = .exe +else + EXT = .out +endif + +CXXFLAGS = -g -std=c++11 -Iinclude -Iexternal/CppLog/include +ODEMXLIB = lib/libOdemxD.a +INCLUDES = ./include ./external/CppLog/include +EXAMPLES = $(wildcard ./examples/*.cpp) +BINARIES = $(EXAMPLES:%.cpp=%$(EXT)) + +$(ODEMXLIB): $(OBJS) + ar cr $@ $^ + +%$(EXT): %.o + $(CXX) $< $(ODEMXLIB) -o $@ + +all: $(ODEMXLIB) + +samples: $(BINARIES) + +clean: + rm -f $(OBJS) $(ODEMXLIB) $(BINARIES) diff --git a/odemx-lite/README b/odemx-lite/README new file mode 100644 index 0000000000000000000000000000000000000000..d8fb7940e2fb0fcdefe93af6186b56ed38b25ec9 --- /dev/null +++ b/odemx-lite/README @@ -0,0 +1,92 @@ +################################################################ +# # +# # +# OO DDDD EEEE M M # +# O O D D E M M M X X # +# O O D D EEEE M M M X # +# O @ O D @ D E M M X X # +# OOOO DDDD EEEEE M M X X # +# # +# ODEMx version 3.0 # +# -------------------- # +# # +# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 # +# Humboldt-Universität zu Berlin and # +# Ralf Gerstenberger and # +# Ronald Kluth # +# # +################################################################ + + Welcome + --------- + Welcome to ODEMx. ODEMx is a C++ library for discrete event simulation. + + + About ODEMx + ------------- +ODEMx is a library for discrete event simulation, which is a +branch of computer simulation. It supports process-based and event- +based simulation models. As such it uses processes and/or events to +model real-world or fictional systems. A process in this context +is a continuous or discrete sequence of actions which are somehow +closely related to each other, for instance they are all 'done' by +one agent. The sequence can be divided into branches, and broken +off by idle periods or synchronisation. Events in this context simply +describe one action in a system that can take place at any time during +a simulation. + + + Copyright and License + ----------------------- +ODEMx is protected by the GNU LESSER GENERAL PUBLIC LICENSE as +described in the file Copying.txt, which should be present in +the ODEMx package; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +The examples in examples/omsi are released under the GNU GENERAL +PUBLIC LICENSE, Version 2. + + Installation + -------------- +For a precise description on how to build ODEMx for your plattform, +please read the file BUILDING. + +There is no installation procedure for ODEMx, at least not in +this version. To use ODEMx in your projects choose the respective +folder that fits your needs best (Gcc on Unix and Linux systems, Msvc +or Msvc7.1 on windows), build the library and finally set-up your +project to use the library. + +Note: +If you are using GCC we recommend to use a version higher than 3.x.x. + +Always take care to activate RTTI in your projects, because ODEMx +depends on this feature. (MSVC and MSCVC7.1 disable RTTI by default) + + + First Steps + ------------- +At first you will have to build ODEMx - see Installation for details. +Afterwards try the examples included. That should give you a good start. +Apart from that you can use them to check whether ODEMx is working properly +on your computer. + +ODEMx includes an online documentation as well. You will need Doxygen +(http://www.doxygen.org) to generate the documentation from the source files. +To do so, go to your build directory and run "make doxygen". This will +build the doxygen documentation and put it into $BUILDIR/doc/html . + + + Contributions + --------------- +ODEMx is based on ODEM (http://odem.sf.net). That's why all contributors of +ODEM could be listed here, too. Instead only those who put their +hands on this code directly will be mentioned. Anyway, we encourage +you to take a look at ODEM and its contributors list as well. + +Ralf Gerstenberger (gerstenb@users.sourceforge.net) +Ronald Kluth +Toralf Niebuhr +Magnus Müller + +EOF diff --git a/odemx-lite/examples/Example_BinT.cpp b/odemx-lite/examples/Example_BinT.cpp new file mode 100644 index 0000000000000000000000000000000000000000..407deb6798c62234940bc3f4dfd06a6431b78071 --- /dev/null +++ b/odemx-lite/examples/Example_BinT.cpp @@ -0,0 +1,228 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_BinT.cpp + * @author Ronald Kluth + * @date created at 2009/04/24 + * @brief Example displaying the basic usage of an unlimited resource with a + * user-defined token type (odemx::synchronization::BinT) + * @since 3.0 + */ + +/** + * @example Example_BinT.cpp + * The basic usage of an unlimited resource is introduced. + * + * There are two processes involved in this simulation. One takes the role of + * a producer of a certain type of items, while the other takes the role of a + * consumer of such items. These two are linked by a temporary storage space, + * i.e. an unlimited resource, where the producer puts new items, which will + * eventually be used by the consumer. + */ + +#include <odemx/odemx.h> +using odemx::base::Process; +using odemx::base::Simulation; +using odemx::data::output::OStreamWriter; +using odemx::toString; + +#include <iostream> +#include <string> +#include <vector> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + + +// forward declaration +odemx::base::SimTime getRandomTime( odemx::random::ContinuousDist& dist ); + +//-----------------------------------------------------------------------globals +// +// We use two random number generators to model the time it takes to produce +// or consume items. +// +odemx::random::Normal productionPeriod( odemx::getDefaultSimulation(), + "Production Period", 10, 2 ); +odemx::random::Normal consumptionPeriod( odemx::getDefaultSimulation(), + "Consumption Period", 3, 2 ); + +//--------------------------------------------------------------------------Item +// +// The struct Item is just a simple type holding the name of some item. It is +// used as token type for the BinT class template. +// +struct Item +{ + Item( const std::string& name ): name( name ) {} + std::string name; +}; + +//-------------------------------------------------------------------ItemStorage +// +// The storage space is simply an instantiation of BinT with Item as its token +// type. We will use it to have the consumer wait for new items to be produced. +// BinT handles this transparently by keeping the consumer in a queue while +// there are not enough items in storage. All the consumer has to do is request +// a number of items. It will be awakened as soon as these become available. +// +typedef odemx::synchronization::BinT< Item > ItemStorage; + +//------------------------------------------------------------------ItemProducer +// +// The producer process creates new named items and puts them into the storage. +// +class ItemProducer: public Process +{ +public: + ItemProducer( ItemStorage& storage ) + : Process( odemx::getDefaultSimulation(), "The Producer" ) + , storage_( &storage ) + {} + +protected: + virtual int main() + { + static std::size_t itemCount = 0; + while( true ) + { + // + // Wait for as long as production requires. + // + holdFor( getRandomTime( productionPeriod ) ); + // + // Fill a vector with newly created items. + // + std::vector< Item > newItems; + for( int i = 5; i > 0; --i ) + { + newItems.push_back( + Item( std::string("Item ") + toString( ++itemCount ) ) ); + } + // + // Add items to the storage bin. + // + storage_->give( newItems ); + // + // Log production of new items + // + info << log( "produced 5 new items" ); + } + return 0; + } + +private: + ItemStorage* storage_; +}; + +//------------------------------------------------------------------ItemConsumer +// +// The consumer process simply waits for items to arrive at the temporary item +// storage. When the requested number of items are available, they are taken +// from the storage and the consumer logs their names upon use. +// +class ItemConsumer: public Process +{ +public: + ItemConsumer( ItemStorage& storage ) + : Process( odemx::getDefaultSimulation(), "The Consumer" ) + , storage_( &storage ) + {} + +protected: + virtual int main() + { + while( true ) + { + // + // By calling take on the BinT object, the consumer enters a queue + // and waits until the requested amount of tokens becomes available. + // It receives them in a vector. + // + std::unique_ptr< std::vector< Item > > newItems = storage_->take( 2 ); + // + // Consumption of the two items is logged to the info channel. + // + info << log( "consumed 2 items" ) + .detail( "first", newItems->front().name ) + .detail( "second", newItems->back().name ); + // + // Wait for as long as it takes to consume items. + // + holdFor( getRandomTime( consumptionPeriod ) ); + } + return 0; + } + +private: + ItemStorage* storage_; +}; + +//--------------------------------------------------------------------------main + +int main( int argc, char* argv[] ) +{ + using namespace odemx; + // + // Since we are using subclasses of Process without providing a simulation + // context, we also have to use the implicitly assumed DefaultSimulation + // here. + // + Simulation& sim = getDefaultSimulation(); + // + // Since we are logging data to the info channel, we must set a data + // consumer. Here, we use a simple writer to std::cout. + // + sim.addConsumer( data::channel_id::info, OStreamWriter::create( std::cout ) ); + // + // Initialize item storage as well as producer and consumer processes. + // + ItemStorage tempStorage( sim, "Temporary Storage" ); + ItemProducer producer( tempStorage ); + ItemConsumer consumer( tempStorage ); + // + // Schedule the processes for immediate execution at SimTime 0. + // + producer.activate(); + consumer.activate(); + // + // Run the simulation with a time limit. Otherwise, both processes would + // run forever and the simulation would never stop. + // + sim.runUntil( 45 ); + return 0; +} +// +// Since random number generators sometimes also generate negative values, +// we cannot simply use samples as time values. This helper function ensures +// that only values greater than or equal to zero are returned. +// +odemx::base::SimTime getRandomTime( odemx::random::ContinuousDist& dist ) +{ + odemx::base::SimTime retVal; + do + { + retVal = (odemx::base::SimTime) dist.sample(); + } + while( retVal <= 0 ); + + return retVal; +} diff --git a/odemx-lite/examples/Example_Connection.cpp b/odemx-lite/examples/Example_Connection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb625334ae065b966a6be5541eb1e84aaef55c42 --- /dev/null +++ b/odemx-lite/examples/Example_Connection.cpp @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Connection.cpp + * @author Ronald Kluth + * @date created at 2010/03/16 + * @brief Example displaying the basic usage of a user-defined coroutine class + * @since 3.0 + */ + +/** + * @example Example_Connection.cpp + * The basic usage of a coroutine implementation is demonstrated + * + * This example demonstrates how protocol connections can be modeled + * in ODEMx as separate coroutines. For this example, we use a very simple + * message class that can only report its type. + * + * Next, a user-defined coroutine class is defined. Its @c run method keeps + * it active for as long as the connection has not been closed. Each time + * the coroutine resumes, it checks whether there is a new message and + * simply prints the type. After that, it yields to return control to its + * caller. + * + * The main program uses this behavior to resume the coroutine several times, + * setting new messages whenever the coroutine yields control. + */ + +#include <iostream> +#include <odemx/odemx.h> + +using namespace odemx; +// +// Simple message class that only has a type and no data +// +class Message +{ +public: + enum Type { T1, T2 }; + + Message( Type t ): type_( t ) {} + Type getType() const { return type_; } +private: + Type type_; +}; +// +// User-defined coroutine subclass that implements a simple protocol +// connection which can maintain an internal state and yield control +// to a caller. +// +class Connection: public coroutine::Coroutine +{ +public: + Connection( base::Simulation& sim ) + : Coroutine( &sim ) + , msg_( 0 ) + , closed_( false ) + {} + + virtual void run() + { + // + // Run until connection gets closed + // + while( ! closed_ ) + { + if( msg_ ) + { + // + // If a message was set for this connection, display the type + // + switch( msg_->getType() ) + { + case Message::T1: + std::cout << "T1" << std::endl; + break; + case Message::T2: + std::cout << "T2" << std::endl; + break; + } + } + // + // Return control to the caller of the coroutine + // + yield(); + } + // + // The connection was closed + // + std::cout << "Connection closed" << std::endl; + } + void setMessage( Message* msg ) + { + msg_ = msg; + } + void close() + { + closed_ = true; + } +private: + Message* msg_; + bool closed_; +}; + +int main() +{ + // + // Create two message objects to pass to the connection object + // + Message m1( Message::T1 ); + Message m2( Message::T2 ); + base::Simulation& sim = getDefaultSimulation(); + // + // Create one coroutine-based connection object and resume it + // several times. + // + Connection c( sim ); + c(); + c.setMessage( &m1 ); + c(); + c.setMessage( &m2 ); + c(); + c.close(); + c(); + return 0; +} diff --git a/odemx-lite/examples/Example_Continuous.cpp b/odemx-lite/examples/Example_Continuous.cpp new file mode 100644 index 0000000000000000000000000000000000000000..509dae5c452769e03f15d9f46560532f45faf319 --- /dev/null +++ b/odemx-lite/examples/Example_Continuous.cpp @@ -0,0 +1,346 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Example_Continuous.cpp + + \author Ralf Gerstenberger + + \date created at 2003/07/02 + + \brief Example for continuous simulations + + This example demonstrates the use of Continuous and ContuTrace. + + \since 1.0 +*/ +/** \example Example_Continuous.cpp + + The basic continuous simulation techniques of ODEMx are introduced. + + Apart from discrete processes a simulation can also contain so called + continuous processes. A discrete process does change the system state + only at discrete moments in simulation time. It uses the + actions defined in its 'main()' function. The progress of time for a + process is realised with functions like 'holdFor', 'activateAt' and so on. + See the basic simulation example for details. + A continuous process instead changes the state of a system continuously. + Such a process could be for example the melting of a block of metal + inside an oven. + At every time, during the melting process, the temperature of the + metal is changed. That means \b every time you measure the temperature you + will get a new value. + Of course real continuity is quite impossible in the discrete world of + our computers. So ODEMx has to approximate continuous state changes with + a step by step computation. +*/ + +#include <odemx/base/Continuous.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/DefaultSimulation.h> +using namespace odemx::base; + +#ifdef ODEMX_USE_CONTINUOUS + +// +// The first Continuous process is very simple. It only defines +// a sinus/co-sinus oscillator. +// +class Oscillator : public Continuous { +public: + // + // The construction of a Continuous object is a little different to + // that of a Process object. You also have to provide the number + // of state-variables used by your process. In case of Oscillator + // we need two variables. + // + Oscillator() : Continuous( odemx::getDefaultSimulation(), "Oscillator", 2 ) {}; + +protected: + // + // The main-function of a continuous process is quite similar to that of + // a discrete process. You can do everything that is possible in Process. + // That's why a continuous can behave just like a discrete process. But + // it can also go through phases of continuous state changes. + // + virtual int main() { + // + // Before you can start the solver, which is computing the continuous + // state changes, you will have to initialise the state variables. + // + state[0]=1; + state[1]=0; + + // + // Than you should set some parameters for the internal solver. These + // parameters include error sensitivity and the step length. + // + // The step length is set with 'setStepLength()'. The first parameter + // sets the minimal step length, while the second defines the maximal + // step length. The internal solver will compute new states in steps. + // Between every step the process holds. The actual length of the step + // taken will depend on numerical errors, peer processes, state events, + // and the parameters provided with 'setStepLength()'. The actual step + // length will not exceed your provided maximum. If the step length has + // to be reduced because of numerical errors or state events it will not + // be reduced below your provided minimum. + // + setStepLength(0.01, 0.1); + + // + // The error sensitivity is set with 'setErrorlimit()'. The first parameter + // defines whether the errors should be considered relative to the value of + // the state variables (0) or absolute (1). The second parameter + // sets the maximum error acceptable (relative or absolute). If the actual + // error exceeds this value the solver will try to reduce the step length. + // If this fails, because the step length is already to small, you will get + // a simulation error. + // + setErrorlimit(0, 0.1); + + // + // Finally, the continuous phase is started with 'integrate()'. It is stopped + // either by a time event, a state event or an interrupt from another process. + // + // The time event is set by the first parameter. If it is 0 the solver will + // run for ever. Otherwise it will run to the given absolute time. If the + // provided time has already passed it will return at once. The return value of + // integrate will be 0 if the time event was hit. If the process is interrupted + // 'integrate()' returns 2. + // + integrate(20.0, 0); + + return 0; + } + + // + // Every Continuous process has to provide its specific 'derivatives()' function. + // In this function you define how the state changes during the time. You do this + // by setting the rate in which a state variable is changed. Although you don't have + // to, you can include the time provided by t in your computation. But never use + // 'getCurrentTime()' to get the time. + // + virtual void derivatives (double t) { + rate[0]=-state[1]; + rate[1]=state[0]; + } +}; + +// +// The FreeFall continuous process needs only one state variable. It demonstrates +// the use of parameter t in 'derivatives()'. The result is an idealistic free fall. +// +class FreeFall : public Continuous { +public: + FreeFall() : Continuous( odemx::getDefaultSimulation(), "FreeFall", 1) {}; + +protected: + virtual int main() { + state[0]=0.0; + + setStepLength(.1,1); + integrate(20.0, 0); + + return 0; + } + + // + // Again, never use getCurrentTime() to include the current time in your + // computation. The reason for this is, that 'derivatives()' is called multiple + // times for each step and these calls are not synchronised to the + // 'official' time in the simulation. + // + virtual void derivatives (double t) { + double g=9.81; + + rate[0]=t*g; + } +}; + +// +// RealFall simulates a 'real fall' which is slowed down by friction. +// +class RealFall : public Continuous { +public: + RealFall() : Continuous( odemx::getDefaultSimulation(), "RealFall", 2 ) {}; + +protected: + // + // As in FreeFall we don't set the error limits. We can do so because + // ODEMx uses default settings for error limits and step length. The + // default for the error limits is a relative (0) error limit of 0.1 . + // + virtual int main() { + state[0]=2.0; + state[1]=0.0; + + setStepLength(.1, 1); + integrate(20.0, 0); + + return 0; + } + + virtual void derivatives (double t) { + double k=0.5; + double g=-9.81; + + rate[0]=state[1]; + rate[1]=g - k*state[1]; + } +}; + +// +// RealBounce finally demonstrates the use of state events. +// +class RealBounce : public Continuous { +public: + RealBounce() : Continuous( odemx::getDefaultSimulation(), "RealBounce", 3 ) {}; + + // + // 'hitGround()' is used to check a state event. The signature + // of functions that can be used as state-event-functions is: + // bool(Process::*)() + // ODEMx uses pointer to member functions if it needs a call-back. + // The advantage is, you can use member functions with full access + // to internal data of your classes to check state events. The + // costs of this design decision is that you will always have to + // cast the address of your state-event-function to the type 'Condition'. + // + // A state function has to return true if a state event has occurred. + // Remember, the computation of state changes is done in steps. Because + // of that it is unlikely to hit a state event exactly. This has to + // be considered when programming a state-event-function. If a state + // event has occurred (or passed) the internal solver starts a binary + // search to get closer to the exact event time. Finally, if it gets close + // enough (minimum step length) the computation is stopped and 'integrate()' + // returns 1. + // + bool hitGround() { + return state[0]<=0.0; + } + +protected: + virtual int main() { + double g=-9.81; + + state[0]=2.0; + state[1]=0.0; + state[2]=g; + + setStepLength(0.01, 0.1); + // + // RealBounce uses the return value of 'integrate()' to control + // the computation. Remember 'integrate()' returns 0 if a + // time event occurred, 2 if the process was interrupted and 1 + // if a state event was detected. + // 'integrate()' is called with the time event 20.0 and the + // state-event-function 'hitGround()'. If the state event + // is hit we reflect the movement 'state[1]=-(0.8*state[1])' + // and continue until the simulation time exceeds 20.0. + // + // EDIT: instead of passing in the above defined "hitground" function, + // it is now also possible to directly pass a lambda function as + // a state event. For compatibility reasons, the Process* argument + // must still be provided, although every nessecery information may + // be captured using a capture default "[&]" + while (integrate(20.0, [&](Process*){ + return state[0]<=0.0; + })) + { + // + // The ball hit the ground and is reflected. + // + if (fabs(state[1])<0.01 && state[0]<0.01) { + // + // We must stop the ball if it has lost to much energy. + // Otherwise we would produce an annoying loop. The + // state event would be hit in every step. + // + state[1]=0.0; + state[2]=0.0; + } + state[1]=-(0.8*state[1]); + } + + return 0; + } + + virtual void derivatives (double t) { + double k=0.5; + + rate[0]=state[1]; + rate[1]=state[2] - k*fabs(state[1]); + rate[2]=0.0; + } +}; + +int main(int argc, char* argv[]) { + + Oscillator* osci = new Oscillator(); + FreeFall* free = new FreeFall(); + RealFall* real = new RealFall(); + RealBounce* bounce = new RealBounce(); + + // + // To follow the state changes we use the class ContuTrace. + // ContuTrace observes a provided continuous process and logs all + // state changes into a text file. The file is managed by ContuTrace. + // The name is either set in the constructor or build from the + // name of the observed continuous process. If you run the simulation + // you will find the 4 text files: + // Oscillator_trace.txt + // FreeFall_trace.txt + // RealFall_trace.txt + // RealBounce_trace.txt + // + + ContuTrace osciTrace(osci), freeTrace(free), realTrace(real), bounceTrace(bounce); + + // + // Continuous processes are activated just like discrete processes. + // + osci->activate(); + free->activate(); + real->activate(); + bounce->activate(); + + // + // We can run the simulation without a time limit because all + // our continuous processes end at 20.0 . + // + odemx::getDefaultSimulation().run(); + + delete bounce; + delete real; + delete free; + delete osci; + + return 0; +} + +#else // ODEMX_USE_CONTINUOUS not defined + +#include <iostream> + +int main( int argc, char* argv[] ) +{ + std::cerr << "ODEMx compiled without support for continuous processes." + << std::endl; + return 0; +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/examples/Example_Control.cpp b/odemx-lite/examples/Example_Control.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9267493e557a7fbf53f558102c3af50fc8cd6f1f --- /dev/null +++ b/odemx-lite/examples/Example_Control.cpp @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Control.cpp + * @author Jonathan Schlue + * @date created at 2016/10/06 + * @brief Example for using Control variables to wait until an arbitrary condition turns true. + * @since 3.1 + */ + +/** + * @example Example_Control.cpp + * The basic usage of Control variables to wait until an arbitrary condition turns true. + * + * There are two processes: a Ping process, and a Pong process. + * ping says "ping" from time to time, by switching pong's controlled bool variable "pinged_". + * pong is waiting for changes to exactly this variable, and whenever it is set to true, pong prints an update about the current + * recognized ping to the console. + */ + +#include <iostream> + +#include <odemx/odemx.h> + +struct Pong: Process +{ + Control<bool> pinged_; + + Pong() :Process(odemx::getDefaultSimulation(), "Pong"), pinged_{false} + {} + +protected: + virtual int main() override + { + + int times_pinged = 0; + + for(;;) + { + waitUntil([&](Process*) { // <-- NOTE the capture default by reference "[&]", to actually always get the current value of "pinged_". + return pinged_; + }, "waiting for a ping", {pinged_}); + + ++times_pinged; + + std::cout << "#" << times_pinged << ": \tgot pinged at time " << getTime() << std::endl; + pinged_ = false; + } + return 0; + } +}; + +struct Ping: Process +{ + Pong* pong_; + + Ping(Pong* pong) :Process(odemx::getDefaultSimulation(), "Ping"), pong_{pong} + {} + +protected: + virtual int main() override + { + + for(int interval = 1;; ++interval) + { + // ping once in a while + holdFor(interval); + pong_->pinged_ = true; + } + return 0; + } +}; + + + +int main() +{ + Pong pong; + Ping ping{&pong}; + ping.hold(); + pong.hold(); + odemx::getDefaultSimulation().runUntil(101); + return 0; +} diff --git a/odemx-lite/examples/Example_Custom_Channel.cpp b/odemx-lite/examples/Example_Custom_Channel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f171527bb01da7cb62933808d882b1f468d87daf --- /dev/null +++ b/odemx-lite/examples/Example_Custom_Channel.cpp @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Custom_Channel.cpp + * @author Ronald Kluth + * @date created at 2010/04/16 + * @brief Example demonstrating how to create and use a new log channel + * @since 3.0 + */ + +/** + * @example Example_Custom_Channel.cpp + * The usage of ODEMx channels is demonstrated. + * + * ODEMx provides 7 separate log channels in order to represent relevant + * logging categories: trace, debug, info, warning, error, fatal, and + * statistics. However, ODEMx users are not limited to these logging + * categories but can instead create their own. This is demonstrated + * by first creating a new channel id and then a consumer class that makes + * use of the channel. + */ + +#include <odemx/odemx.h> +// +// First we use a macro to create a new channel ID. This value will be +// created in namespace odemx::data::channel_id. +// +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( clock, 99 ); +// +// Next, we define a simple producer class that has a shared_ptr member +// for the ODEMx log channel type. During construction, this pointer +// gets initialized be requesting a new channel pointer from the simulation +// context. The method @c useChannel then demonstrates how this channel +// can be put to use. +// +class CustomProducer: public odemx::data::Producer { +public: + CustomProducer( odemx::base::Simulation& sim, const odemx::data::Label& label ) + : Producer( sim, label ) + { + clock = sim.getChannel( odemx::data::channel_id::clock ); + } + void useChannel() { + clock << log( "using my own channel" ); + } +private: + std::shared_ptr< Log::Channel< odemx::data::SimRecord > > clock; +}; + +int main() +{ + odemx::base::Simulation& sim = odemx::getDefaultSimulation(); + // + // After creating a new producer object, we enable the default logging + // functionality of ODEMx an choose to log output to the console. + // Then, the method @c useChannel is called to produce some + // text output on the console. + // + CustomProducer p( sim, "Custom Producer" ); + sim.enableDefaultLogging( odemx::data::output::STDOUT ); + p.useChannel(); +} diff --git a/odemx-lite/examples/Example_DiningPhilosophers.cpp b/odemx-lite/examples/Example_DiningPhilosophers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81744e2239ef26193cb4544d041179c6d020449a --- /dev/null +++ b/odemx-lite/examples/Example_DiningPhilosophers.cpp @@ -0,0 +1,86 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_DiningPhilosophers.cpp + * @author Ronald Kluth + * @date created at 2010/04/24 + * @brief Example showing a variation of the dining philosophers problem + * @since 3.0 + */ + +/** + * @example Example_DiningPhilosophers.cpp + * + * There are 800 seats and as many philosophers and forks on one table. + * Philosophers either spend time thinking or eating. But the latter is only + * possible if two forks are available. As this Simulation is fairly time + * consuming, it was used to measure ODEMx performance. + */ + +#include <odemx/odemx.h> +#include <deque> + +class Philosopher: public odemx::base::Process { +public: + Philosopher( bool& fork1, bool& fork2, odemx::base::SimTime timePeriod ) + : Process( odemx::getDefaultSimulation(), "Philosopher" ) + , fork1( fork1 ), fork2( fork2 ), timePeriod( timePeriod ) + {} +private: + virtual int main() { + while( true ) { + do { // thinking + spendTime(); + } while( ! takeForks() ); + // forks acquired, start eating + spendTime(); + returnForks(); + } + return 0; + } +private: + bool& fork1; + bool& fork2; + int timePeriod; +private: + bool takeForks() { + if( fork1 && fork2 ) { + fork1 = fork2 = false; + return true; + } + return false; + } + void returnForks() { fork1 = fork2 = true; } + void spendTime(){ holdFor( timePeriod ); } +}; + +int main() { + std::deque< Philosopher* > phils; + std::deque< bool > forks; + int seats = 800; + for( int i = 0; i < seats; ++i ) { forks.push_back( true ); } + for( int i = 0; i < seats - 1; ++i ) { + phils.push_back( new Philosopher( forks[ i ], forks[ i + 1 ], 10 ) ); + } + phils.push_back( new Philosopher( forks[ forks.size() - 1 ], forks[ 0 ], 10 ) ); + + for( int i = 0; i < phils.size(); ++i ) { phils[ i ]->activate(); } + odemx::getDefaultSimulation().runUntil( 10000 ); + std::for_each( phils.begin(), phils.end(), odemx::DeletePtr< Philosopher >() ); +} diff --git a/odemx-lite/examples/Example_Event.cpp b/odemx-lite/examples/Example_Event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a7cf7ec7826b8970f9f1c1925d467e48da2929b --- /dev/null +++ b/odemx-lite/examples/Example_Event.cpp @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Event.cpp + * @author Ronald Kluth + * @date created at 2008/12/08 + * @brief Example displaying the basic techniques for realizing an event-based + * simulation with ODEMx. + * @since 2.1 +*/ + +/** + * @example Example_Event.cpp + * Further basic simulation techniques of ODEMx are introduced. + * + * An event-based simulation contains a number of event objects that describe + * certain event occurrences in a model. An event represents one atomic + * action. These actions are timeless. In this example, several scheduling + * operations are presented together with an example event class. + */ + +#include <odemx/base/Event.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/DefaultSimulation.h> +using odemx::base::Event; +using odemx::base::Simulation; + +#include <iostream> +using std::cout; +using std::endl; + +//--------------------------------------------------------------------------Tick +// +// This example Event represents simple SimTime ticks. It outputs a '*' every +// full tick in SimTime. +// +class Tick: public Event +{ +public: + // + // Every event object needs a reference to the simulation context it belongs + // to. However, ODEMx provides a default simulation context, to enable use + // of processes and events without having to define a customized simulation + // class. Events, like all simulation elements, require a label for + // identification. ODEMx ensures that labels are unique within the same + // simulation context by appending numbers to duplicate labels. + // + Tick(): Event( odemx::getDefaultSimulation(), "Tick" ) {} + // + // This method overrides the pure virtual method of the base class Event. + // It describes the corresponding action in a model if this event occurs. + // Here, we simply output a '*' and reschedule the event to model the + // recurring ticks of a clock. + // + virtual void eventAction() + { + scheduleIn( 1 ); + cout << " * "; + } +}; + +//--------------------------------------------------------------------------main + +int main( int argc, char* argv[] ) +{ + // + // For this example, the default simulation context is used. In more complex + // applications it is recommended to provide a customized simulation class. + // + Simulation& sim = odemx::getDefaultSimulation(); + // + // Using the default constructor, our Tick event will use the default + // simulation context that is also referenced by 'sim'. + // + Tick ticker; + // + // The event object is just created at this point. It will not be executed + // because it is not scheduled. An event can be scheduled by any of these + // methods: + // + // 'schedule()' + // 'scheduleIn()' + // 'scheduleAt()' + // 'scheduleAppend()' + // 'scheduleAppendIn()' + // 'scheduleAppendAt()' + // + // 'schedule()' and 'scheduleAppend()' are equal to + // 'scheduleIn( 0 )' and scheduleAppendIn( 0 ), respectively. + // 'scheduleAt( t )' and 'scheduleAppendAt( t )' are equal to + // 'scheduleIn( t - now )' and 'scheduleAppendIn( t - now )'. + // + ticker.scheduleAt( 1 ); + // + // There are three ways to compute a simulation. Firstly, you can 'run()' + // the simulation until it is finished. A simulation is finished if there + // is no active process or event scheduled, or if it is stopped with + // 'exitSimulation()'. Secondly, you can compute a simulation 'step()' by + // step. Thirdly, you can run a simulation until a given SimTime is + // reached with 'runUntil()'. + // + // Because Tick events will reschedule themselves forever, we should not use + // 'run()'. Instead we try both 'step()' and 'runUntil()'. + // + cout << "Basic Event Simulation Example\n"; + cout << "==============================\n"; + + for( int i = 1; i < 5; ++i ) + { + sim.step(); + cout << "\n" << "Step " << i << ": time = " << sim.getTime() << "\n"; + } + + cout << "\n" << "continue until SimTime 6 is reached:"; + sim.runUntil( 6 ); + cout << "\n" << "time = " << sim.getTime() << "\n"; + + cout << "==============================" << endl; + return 0; +} + +//----------------------------------------------------------------program output +// +// Basic Event Simulation Example +// ============================== +// * +// Step 1: time = 1 +// * +// Step 2: time = 2 +// * +// Step 3: time = 3 +// * +// Step 4: time = 4 +// +// continue until SimTime 6 is reached: * * +// time = 6 +// =============================== +// +// In contrast to the basicProcess example there is a '*' at step 1 because +// event actions are atomic. Keep in mind that always all of the statements +// in eventAction() are executed, even if there are scheduling calls. In this +// case, the same Event object is rescheduled, but it still outputs the '*'. +// Once an Event's action is started, it cannot be stopped or postponed. +// diff --git a/odemx-lite/examples/Example_Filter.cpp b/odemx-lite/examples/Example_Filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17d9e3bbd2a21bf31a6d5c7a5f072b4dccb417e2 --- /dev/null +++ b/odemx-lite/examples/Example_Filter.cpp @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file examples/Example_Filter.cpp + * @author Ronald Kluth + * @date created at 2010/04/24 + * @brief Example demonstrating how to use a SimRecordFilter + * @since 3.0 + */ + +/** + * @example Example_Filter.cpp + * The usage of the ODEMx log record filter class is shown. + * + * All four methods of filtering simulation records are shown in the + * main function. Filtering can be done by record text, record scope, + * producer label, or producer type. + */ + +#include "Example_Producer_DebugStopWatch.h" +#include <iostream> +using namespace odemx; + +int main() { + typedef std::shared_ptr< data::SimRecordFilter > FilterPtr; + FilterPtr filter = data::SimRecordFilter::create(); + + base::Simulation& sim = getDefaultSimulation(); + sim.enableDefaultLogging( data::output::STDOUT ); + sim.setFilter( filter ); + + // + // The construction of the DebugStopWatch is filtered here. + // + filter->addRecordText() << "construction"; + DebugStopWatch watch( sim, "Stop Watch" ); + + // + // The scope filters all output from a class in hierarchy, in this case + // the records sent by class DebugStopWatch. Therefore, only the base class + // records from StopWatch may pass here. + // + filter->addRecordScope() << typeid( DebugStopWatch ); + watch.start(); + watch.stop(); + + // + // Filtering by label means blocking everything that is sent by this object. + // So, no output happens when calling @c start. + // + filter->addProducerLabel() << "Stop Watch"; + watch.start(); + + // + // Resetting the filter removes all previously added values. However, + // adding the producer type is different than using a scope because + // this will now also filter all records, but not only from one object + // but all objects of class DebugStopWatch. + // + filter->resetFilter(); + filter->addProducerType() << typeid( DebugStopWatch ); + watch.stop(); +} diff --git a/odemx-lite/examples/Example_Matryoshka_Simulation.cpp b/odemx-lite/examples/Example_Matryoshka_Simulation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f0bf0e9bcd8e2b9a33ee03eadbd19d7eb07cf77 --- /dev/null +++ b/odemx-lite/examples/Example_Matryoshka_Simulation.cpp @@ -0,0 +1,184 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Example_Matryoshka_Simulation.cpp + + \author Ralf Gerstenberger + + \date created at 2002/12/14 + + \brief Example for recursive simulations + + This example shows the techniques for + realising a recursive simulation with ODEMx. + + \since 1.0 +*/ +/** \example Example_Matryoshka_Simulation.cpp + Recursive simulations are + introduced. + + One of the unique features of ODEMx is the possibility to run a simulation inside + another simulation without unwanted side-effects. This could come in handy if you + want to simulate an agent network for instance. Agents have an internal model of + their environment, which they use to make their decisions. With ODEMx such an + agent could be modelled with an internal (simplified) simulation. Another example + could be a very complex simulation task. With ODEMx you could split the model into + several blocks, develop each one as a simulation on its own, and plug them together + at the end. +*/ + +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +using odemx::base::Process; +using odemx::base::Simulation; + +#include <iostream> +using std::cout; +using std::endl; + +// +// In this example we demonstrate the possibility to cascade simulations in a recursive +// simulation called Matryoshka. Like the Russian puppet inside a puppet inside a puppet +// inside ... +// +// A user defined simulation is a class derived from Simulation. Every process or model +// component requires a pointer to its simulation. The user defined simulation can provide +// its processes with additional data. Furthermore, a user defined simulation must implement +// the 'initSimulation()' function to start its processes and to do specific initialisations. +// +class Matryoshka +: public Simulation +{ + // + // The simulation contains only the process Proc. + // This process expects a Matryoshka-simulation as + // environment. Defining the process as an inside + // class of Matryoshka is of course not required. + // + class Proc + : public Process + { + public: + Proc( Matryoshka& sim ) + : Process( sim, "Proc" ) + {} + + protected: + // + // In its 'main()' function the process gets a pointer to + // its simulation. After a cast (the dynanmic_cast could + // be spared) the process can access the data provided by + // its simulation. + // + virtual int main() + { + int i; + Matryoshka& sim = dynamic_cast< Matryoshka& >( this->getSimulation() ); + int level = sim.getLevel(); + + for( i = level; i > 0; --i ) + { + cout << ' '; + } + + if( level % 2 > 0 ) + { + cout << "Di " << level << endl; + } + else + { + cout << "Da " << level << endl; + } + + // + // After some outputs the process starts the recursion. + // + if( level > 0 ) + { + Matryoshka m( level - 1 ); + m.run(); + } + + for( i = level; i > 0; --i ) + { + cout << ' '; + } + + if( level % 2 > 0 ) + { + cout << "Di " << level << endl; + } + else + { + cout << "Da " << level << endl; + } + return 0; + } + }; + + Proc p; + unsigned int mLevel; + +public: + // + // Because of the recursion Matryoshka needs the additional + // parameter 'level'. + // + Matryoshka( unsigned int level ) + : Simulation( "Matryoshka" ) + , p( *this ) + , mLevel( level ) + {} + + ~Matryoshka() + { + //delete p; + } + + // + // 'level' is the recursion parameter of the Matryoshka simulation. + // + unsigned int getLevel() { return mLevel; } + +protected: + // + // If you are defining your own simulation class you have to provide 'initSimulation' + // to initialise the simulation. This function is called when the simulation is started + // for the first time. + // + virtual void initSimulation() + { + p.activate(); + } +}; + +// +// The 'main' function looks a bit deserted in this example. Almost everything +// is done in the simulation. The advantage is, you can 'reuse' the simulation +// as it is. +// +int main(int argc, char* argv[]) +{ + // Start the first simulation to kick off the recursion + Matryoshka m( 10 ); + m.run(); + + return 0; +} + diff --git a/odemx-lite/examples/Example_Parallel_Simulation.cpp b/odemx-lite/examples/Example_Parallel_Simulation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a63f99ee98535fc89a43d712c5bc19e37496c908 --- /dev/null +++ b/odemx-lite/examples/Example_Parallel_Simulation.cpp @@ -0,0 +1,224 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Example_Parallel_Simulation.cpp + + \author Ralf Gerstenberger + + \date created at 2002/12/14 + + \brief Example for multiple (parallel) simulations + + This example shows the techniques for realising + multiple (parallel) simulations in one program. + + \since 1.0 +*/ +/** \example Example_Parallel_Simulation.cpp + Multiple (parallel) simulations in one program are + introduced. + + As shown in the example for simulations inside simulations, it is + possible to have multiple simulations in one program. These simulations + can be computed one after another or 'parallel'. In this example both + situations are presented. +*/ + +#include <iostream> +using namespace std; + +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +#include <odemx/synchronization/WaitQ.h> +using namespace odemx::base; +using namespace odemx::synchronization; + +// +// In this example we demonstrate multiple parallel simulations. We have +// two simulations (SimA and SimB) which are at first computed one after +// another and then parallel. +// +// SimA contains two processes (Master and Slave) which cooperate through +// an instance of WaitQ. Master uses the function 'coopt()' which returns a +// waiting slave. Slave calls the function 'wait()' to show its readiness. +// Both functions block the execution of the active process if an immediate +// interaction between a slave and a master is not possible. +// +class SimA : public Simulation { + // process types of SimA + class Master : public Process { + public: + Master(SimA& sim) + : Process(sim, "Master") {} + + protected: + virtual int main() { + SimA& sim = dynamic_cast<SimA&>( this->getSimulation()); + Slave* s=0; + + cout << getLabel() << " coopt" << endl; + s = dynamic_cast<Slave*>(sim.getQueue()->coopt()); + + // + // The function 'activateAfter()' causes the activation + // of a process after another. + // + s->activateAfter(this); + + cout << getLabel() << " coopt finished" << endl; + + return 0; + } + }; + + class Slave : public Process { + public: + Slave(SimA& sim) + : Process(sim, "Slave") {} + + protected: + virtual int main() { + SimA& sim = dynamic_cast<SimA&>(getSimulation()); + + cout << getLabel() << " wait" << endl; + sim.getQueue()->wait(); + cout << getLabel() << " wait finished" << endl; + + return 0; + } + }; + + Master* m; + Slave* s; + WaitQ* q; + +public: + SimA(SimulationObserver* o = 0) + : Simulation("SimA", o), m(0), s(0), q(0) {} + + ~SimA() { + delete m; + delete s; + delete q; + } + + WaitQ* getQueue() {return q;} + +protected: + virtual void initSimulation() { + m = new Master(*this); + s = new Slave(*this); + q = new WaitQ(*this, "queue"); + + m->activate(); + s->activate(); + } +}; + +// +// SimB contains a process called Loop which 10 times writes +// its label and holds for 1 time unit. +// +class SimB : public Simulation { + // process types of SimA + class Loop : public Process { + public: + Loop(SimB& sim, ProcessObserver* o = 0) + : Process(sim, "Loop", o) {} + + protected: + virtual int main() { + for (int i= 0; i<10; ++i) { + cout << getLabel() << i << endl; + holdFor(1); + } + + return 0; + } + }; + +public: + SimB(SimulationObserver* o = 0) + : Simulation("SimB", o), l(0) {} + + ~SimB() { + delete l; + } + + Loop* l; + +protected: + virtual void initSimulation() { + l=new Loop(*this); + + l->activate(); + } +}; + +// +// The main function runs at first a simulation of type SimA, +// than a simulation of type SimB and finally a simulation of +// type SimA parallel to a simulation of type SimB (step by step). +// +int main(int argc, char* argv[]) { + + // + // Run simulation of type SimA + // + cout << "Part 1" << endl; + for (int i=0; i<5; ++i) { + SimA s; + s.run(); + } + cout << "Simulation A has run 5 times."; + + // + // Run simulation of type SimB + // + cout << endl << "Part 2" << endl; + { + SimB s; + s.run(); + } + cout << "Simulation B has run once."; + + // + // Run simulations of type SimA and type SimB + // + cout << endl << "Part 3 -- Running two interleaved simulations" << endl; + { + SimA s1; + SimB s2; + + s1.step(); + s2.step(); + + while ( !(s1.isFinished() && s2.isFinished()) ) { + + if (!s1.isFinished()) + s1.step(); + + if (!s2.isFinished()) + s2.step(); + } + } + + cout << endl << "Finished" << endl; + return 0; +} + diff --git a/odemx-lite/examples/Example_Port2.cpp b/odemx-lite/examples/Example_Port2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd275fb9d6eaa167293b8be91b5eb67cab7c1e3a --- /dev/null +++ b/odemx-lite/examples/Example_Port2.cpp @@ -0,0 +1,376 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Example_Port2.cpp + + \author Ralf Gerstenberger + + \date created at 2003/07/28 + + \brief Port2 example from ODEM + + Port2 example from ODEM transferred to ODEMx. +*/ + +/** \example Example_Port2.cpp + This example demonstrates a migration from ODEM to ODEMx. + The original Port2 simulation was taken from ODEM and adjusted + to run with ODEMx. Port2 simulates a port with tides. The + original source-code is preserved in this file to show the + differences. +*/ + +/* +#include "odem.h" + + ODEMx requires different include files than ODEM. The + most simple solution is to include odemx.h. This file + in turn includes other header from ODEMx. All classes + of ODEMx are placed in the namespace ODEMx. In this simple + example it is safe to use the whole namespace. +*/ +#include <odemx/odemx.h> +using namespace odemx::base; +using namespace odemx::random; +using namespace odemx::synchronization; + +#include <vector> +using namespace std; + + +/* +#ifdef _USE_GL +#include "grtrace.h" +#endif + + ODEMx does not support the GrTrace from ODEM. + + In ODEMx all model components require a pointer to the + simulation. In general a user would provide a class for + its special simulation which would inherit the ODEMx + Simulation class. But for convenience ODEMx also contains + a default simulation class. The function getDefaultSimulation() + returns a pointer to an object of this class. +*/ + +Simulation* sim = &odemx::getDefaultSimulation(); + +/* + The names of the following classes have not been changed between + ODEM and ODEMx. +*/ +Res* tugs; // Schlepper +Res* jetties; // Anlegeplaetze +CondQ* dockq; +ContinuousDist* next; +ContinuousDist* discharge; + +/* +class Boat : public Discrete { +public: + int main (); + Boat() : Discrete("boat"){} +}; + + The ODEM base class Discrete for active model components + has been replaced by the class Process in ODEMx. As in ODEM + a user has to provide an implementation of the function + virtual int main(). The constructor of Process requires, + in addition to a name, a pointer to the simulation class. + Another difference between ODEM and ODEMx is, that call-backs + used for coding conditions or selections are member-functions + (bool cond1()). +*/ +class Boat : public Process { +public: + int main (); + Boat() : Process( *sim, "boat"){} + + bool cond1(); +}; + +/* +bool cond1(); +*/ + +int Boat::main() { +// im Dock + jetties->acquire(1); + + /* + dockq->waituntil(cond1); + + The interface of CondQ has changed. In this example + we have to use wait(...) instead of waituntil(...). + The cast is required because of the decision to use + member functions for call-backs. We think the advantages + outweigh the disadvantages of this cast. + */ + dockq->wait([&](Process* self) { + return static_cast<Boat*>(self)->cond1(); + }); + + tugs->acquire(2); + + /* + hold(2.0); + + Most scheduling functions have been changed between ODEM and ODEMx. + hold() for instance is now replaced by a holdFor(). + */ + holdFor(2); + + tugs->release(2); + dockq->signal(); + +// Loeschen der Ladung + /* + hold(discharge->sample()); + */ + holdFor(static_cast< SimTime >( discharge->sample() )); + +// ablegen + tugs->acquire(1); + + /* + hold (2.0); + */ + holdFor(2); + + tugs->release(1); + jetties->release(1); + dockq->signal(); + + return 0; +} + +/* +class Tide : public Discrete { +public: + static bool low; + Tide(): Discrete("tide") {} + int main (); + + (see the comments for Boat) +}; +*/ +class Tide : public Process { +public: + static bool low; + Tide(): Process( *sim, "tide") {} + int main (); +}; + +bool Tide::low = false; + +/* +bool cond1() { + + (see the comments for Boat) +*/ +bool Boat::cond1() { + /* + return (tugs->avail() >=2) && !Tide::low; + + The function avail() is replaced by getTokenNumber() + in ODEMx. + */ + return (tugs->getTokenNumber() >=2) && !Tide::low; +} + +int Tide::main() { + for (;;) { + // low + low = true; + + /* + hold(4.0); + */ + holdFor(4); + + low = false; + dockq->signal(); + + // high + /* + hold(9.0); + */ + holdFor(9); + } + return 0; +} + +/* +class Arrival : public Discrete { +public: + Boat *b; + Arrival(): Discrete("arrival") {} + int main (); +}; + + (see the comments for Boat) +*/ +class Arrival : public Process { + vector<Boat*> generatedBoats; +public: + Boat *b; + Arrival(): Process( *sim, "arrival") {} + ~Arrival() { + vector<Boat*>::iterator i; + for ( i = generatedBoats.begin(); i != generatedBoats.end(); ++i ) + delete *i; + } + int main (); +}; + + +int Arrival::main() { + for (;;) { + b = new Boat; + generatedBoats.push_back(b); + /* + b->start(NOW); + hold(next->sample()); + + The function start() is not available in + ODEMx. In ODEMx any hold* or activate* function + can be used to start a new process. + */ + b->hold(); + holdFor(static_cast< SimTime >( ::next->sample() )); + } + return 0; +} + +int main(int argc, const char* argv[]) { +/* + InitializeOdemLib(argc, argv); + +#ifdef _USE_GL + trace().addClient(new GrTrace); +#endif + trace().start(); + + It is not necessary to initialise ODEMx. + + The trace system has changed between ODEM and ODEMx. + The trace management is done by the simulation class. + A new trace is added with the function addConsumer(...). + The trace is controlled with startTrace(), stopTrace(), + pauseTrace() and continueTrace(). HtmlTrace logs the + simulation events in a html file. It also provides a simple + filter to reduce the output. Without a filter the ODEMx trace + logs much more events than its predecessor in ODEM. In + this example the filter is set to produce an ODEM-like output. + + In ODEMx several reports are available in one simulation to the + cost of explicitly creating report objects (the class + HtmlReport is provided by ODEMx) and registering + model components to the different reports. + + The results of this simulation can be found in the files + 'Port2_Trace.html' and 'Port2_Report.html'. Trace and report + of the original ODEM version have been added to the ODEMx package + for you to compare output and results. They can be found + along with the Port2.cpp file ('Port2_Trace.txt' and + 'Port2_Report.txt'). +*/ +// HtmlTrace trace(sim, "Port2_Trace.html"); +// HtmlReport report(sim, "Port2_Report.html"); + +// trace.setFilter("all; mtn:changeState, changeExTime, create, time," +// "execute process, init, execute, changeTokenNumber," +// "current process, run until, sleep"); +// sim->addConsumer(&trace); +// sim->startTrace(); + + Arrival *a = new Arrival; + Tide *t = new Tide; + +/* + next = new NegativeExponential("next boat", 0.1); + discharge = new Normal("discharge", 14.0, 3.0); + tugs = new Res("tugs", 3); + jetties = new Res("jetties", 2); + dockq = new CondQ("dockq"); + + As already mentioned, in ODEMx most model components require + a pointer to an object of the simulation class. Res in + addition does need a maximum token number which can be larger + than the initial number of available token. +*/ + ::next = new NegativeExponential(*sim, "next boat", 0.1); + discharge = new Normal(*sim, "discharge", 14.0, 3.0); + tugs = new Res(*sim, "tugs", 3, 3); + jetties = new Res(*sim, "jetties", 2, 2); + dockq = new CondQ(*sim, "dockq"); + +// report.addProducer(next); +// report.addProducer(discharge); +// report.addProducer(tugs); +// report.addProducer(jetties); +// report.addProducer(dockq); + + /* + a->start(NOW); + t->start(DELAY,1); + main_Discrete()->hold(50.0); + + (see Arrival::main comments as well) + + In ODEMx the global main function is not integrated as a + process. The simulation control is instead realised by the + functions run(), runUntil(...) and step(). + */ + a->activate(); + t->activateIn(1); + sim->runUntil(50); + + /* + trace().pause(); + */ +// sim->pauseTrace(); + + /* + main_Discrete()->hold(28.0*24.0-50.0); + */ + sim->runUntil(28*24); + + /* + report(); + + The function generateReport() has to be called for every report. + Registered model components mustn't be deleted because + generateReport() gathers data from them. + */ +// report.generateReport(); + +// sim->stopTrace(); + sim->exitSimulation(); + + delete a; + delete t; + delete ::next; + delete discharge; + delete tugs; + delete jetties; + delete dockq; + + return 0; +} + diff --git a/odemx-lite/examples/Example_Process.cpp b/odemx-lite/examples/Example_Process.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb18c3ea847d6543c84e1f2a0888f18d223b9d3b --- /dev/null +++ b/odemx-lite/examples/Example_Process.cpp @@ -0,0 +1,184 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Process.cpp + * @author Ralf Gerstenberger + * @date created at 2002/08/26 + * @brief Example demonstrating basic ODEMx process simulation techniques + * @since 1.0 +*/ + +/** + * @example Example_Process.cpp + * + * The basic simulation techniques required for ODEMx process simulations + * are introduced. + * + * A process simulation contains a number of processes that describe + * active elements in a model. A process contains a description of its behavior, + * a sequence of actions. These actions are timeless. Time consumption is + * realized with special time operations. In this example several of these + * time operations are presented together with an example process. + */ + +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/DefaultSimulation.h> +using odemx::base::Process; +using odemx::base::Simulation; + +#include <iostream> +using std::cout; +using std::endl; + +//-------------------------------------------------------------------------Clock +// +// This example Process is a simple SimTime clock. It outputs a '*' every full +// tick in SimTime. +// +class Clock: public Process +{ +public: + // + // We label all instances of this class 'Clock'. ODEMx ensures uniqueness + // of labels on its own to prevent confusion. It will add a number to the + // label if more than one Clock object is created in the same simulation + // context. + // + // When we create any kind of Process object, we have to provide a reference + // to the simulation context we want it to participate in. If the + // constructor of Process is called without a simulation context, it will + // use the default simulation context. + // + // Here, we choose to provide a simulation context. + // + Clock( Simulation& sim ): Process( sim, "Clock" ) {} + // + // The behavior of a user process must be defined by an implementation of + // the pure virtual function 'int main()'. The return value of this + // function is stored in the Process object and can be accessed via the + // method 'getReturnValue()'. As long as 'main()' has not finished, the + // return value is not valid. You can use the Process method 'hasReturned()' + // to check this condition. + // + virtual int main() + { + // + // Because our process has a recurring behavior pattern, we implement + // its life cycle by using a loop. + // + while( true ) + { + // + // Since we are implementing a simple clock, we need a means to let + // the SimTime pass. Here, we use the member function 'holdFor()', + // which requires a time period as parameter. We could also use + // 'activateIn()' instead. The difference between these two is seen + // if there is more than one process scheduled at the same time. + // 'holdFor()' would than schedule the current process in the last + // position while 'activateIn()' would schedule the current process + // as the first one at that particular time. Therefore, hold... and + // activate... functions can be used to choose between fifo or lifo + // scheduling. + // + holdFor( 1 ); + + cout << " * "; + } + return 0; + } +}; + +//--------------------------------------------------------------------------main + +int main( int argc, char* argv[] ) +{ + // + // For this example we can use the DefaultSimulation. In more complex + // applications it is recommended to provide a customized simulation class. + // + Simulation& sim = odemx::getDefaultSimulation(); + Clock clock( sim ); + // + // The new process is just created at this point. It will not be executed + // because it has not been activated yet. A process can be activated by any + // of these methods: + // + // 'hold()' + // 'holdFor()' + // 'holdUntil()' + // 'activate()' + // 'activateIn()' + // 'acitvateAt()' + // + // 'hold()' and 'activate()' are equal to 'holdFor( 0 )' and + // 'activateIn( 0 )'. 'holdUntil( t )' and 'activateAt( t )' + // are equal to 'holdFor( t - now )' and 'activateIn( t - now )'. + // + clock.activate(); + // + // There are three ways to compute a simulation. Firstly, you can 'run()' + // the simulation until it is finished. A simulation is finished if there + // is no active process or event scheduled, or if it is stopped with + // 'exitSimulation()'. Secondly, you can compute a simulation 'step()' by + // step. Thirdly, you can run a simulation until a given SimTime is + // reached with 'runUntil()'. + // + // Because Clock processes are running forever, we should not use + // 'run()'. Instead we try both 'step()' and 'runUntil()'. + // + cout << "Basic Process Simulation Example\n"; + cout << "================================\n"; + + for( int i = 1; i < 5; ++i ) + { + sim.step(); + cout << "\n" << "Step " << i << ": time = " << sim.getTime() << "\n"; + } + + cout << "\n" << "continue until SimTime 6 is reached:"; + sim.runUntil( 6 ); + cout << "\n" << "time = " << sim.getTime() << "\n"; + + cout << "================================" << endl; + + return 0; +} + +//----------------------------------------------------------------program output +// +// Basic Process Simulation Example +// ================================ +// +// Step 1: time = 0 +// * +// Step 2: time = 1 +// * +// Step 3: time = 2 +// * +// Step 4: time = 3 +// +// continue until SimTime 6 is reached: * * * +// time = 6 +// ================================ +// +// Keep in mind that at step 1 our clock will not output a '*' because that is +// the first step until the 'holdFor( 1 )' statement is reached. Only after +// that, the clock starts ticking, so to speak. +// diff --git a/odemx-lite/examples/Example_Process_Deletion.cpp b/odemx-lite/examples/Example_Process_Deletion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3b8abf35bcd9977a9c0426b0858e9723fef25b4 --- /dev/null +++ b/odemx-lite/examples/Example_Process_Deletion.cpp @@ -0,0 +1,96 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Process_Deletion.cpp + * @author Ronald Kluth + * @date created at 2010/04/24 + * @brief Example demonstrating how to delete terminated processes + * @since 3.0 + */ + +/** + * @example Example_Process_Deletion.cpp + * The usage of ODEMx process memory management is demonstrated. + * + * For this purpose, Processes are created, activated and immediately + * terminated after running once. These Process objects are then automatically + * destroyed. + */ + +#include <odemx/odemx.h> +using namespace odemx; +using namespace odemx::base; + +#include <iostream> + +// +// Process class that shows when a process is active and thus becomes terminated +// after finishing its main function. Logging in the destructor shows when +// the objects get destroyed. +// +class TestProcess: public Process { +public: + TestProcess(): Process( odemx::getDefaultSimulation(), "TestProcess" ) {} + ~TestProcess() { info << log( "process destroyed" ); } + virtual int main() + { + info << log( "active" ); + return 0; + } +}; + +// +// A generator event class that creates and schedules processes. +// +class Generator: public Event { +public: + Generator( int count ): Event( odemx::getDefaultSimulation(), "Generator" ) + , count_( count ) {} + virtual void eventAction() + { + for( int i = 0; i < count_; ++i ) + { + info << log( "new process" ); + Process* p = new TestProcess(); + p->activateIn( 10 ); + } + } +private: + int count_; +}; + +int main() +{ + Simulation& sim = getDefaultSimulation(); + // + // In order to have ODEMx delete terminated processes during a simulation + // run, the method @c autoDeleteProcesses must be called. + // + sim.autoDeleteProcesses(); + sim.addConsumer( data::channel_id::info, + data::output::OStreamWriter::create( std::cout ) ); + // + // All processes are created and scheduled at once, but each is + // deleted right after its execution when control goes back to the + // simulation context. + // + Generator gen( 5 ); + gen.schedule(); + sim.runUntil( 15 ); +} diff --git a/odemx-lite/examples/Example_Producer_DebugStopWatch.h b/odemx-lite/examples/Example_Producer_DebugStopWatch.h new file mode 100644 index 0000000000000000000000000000000000000000..50ec335af09007d7ecc4147347c9af29420d79da --- /dev/null +++ b/odemx-lite/examples/Example_Producer_DebugStopWatch.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Producer_DebugStopWatch.h + * @author Ronald Kluth + * @date created at 2010/04/13 + * @brief Example demonstrating the use of ODEMx's debug channel within a producer class + * @since 3.0 + */ + +/** + * @example Example_Producer_DebugStopWatch.h + * The usage of ODEMx log channel @c debug is shown. + * + * For this purpose, a new log data producer is derived from the class + * @c StopWatch. It extends this class by hiding its methods @c start and @c stop + * in order to add debug statements to the calls. + */ + +#ifndef EXAMPLE_PRODUCER_DEBUGSTOPWATCH_INCLUDED +#define EXAMPLE_PRODUCER_DEBUGSTOPWATCH_INCLUDED + +#include "Example_Producer_StopWatch.h" + +class DebugStopWatch: public StopWatch { +public: + DebugStopWatch( odemx::base::Simulation& sim, const odemx::data::Label& label ) + : StopWatch( sim, label ) { + debug << log( "construction" ).scope( typeid( DebugStopWatch ) ); + } + ~DebugStopWatch() { + debug << log( "destruction" ).scope( typeid( DebugStopWatch ) ); + } + void start() { + debug << log( "started" ).scope( typeid( DebugStopWatch ) ); + StopWatch::start(); + } + void stop(){ + debug << log( "stopped" ).scope( typeid( DebugStopWatch ) ); + StopWatch::stop(); + } +}; + +#endif /* EXAMPLE_PRODUCER_DEBUGSTOPWATCH_INCLUDED */ diff --git a/odemx-lite/examples/Example_Producer_LoggingManager.cpp b/odemx-lite/examples/Example_Producer_LoggingManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14d20d7314b7c2a610eb18c71935540e87c32171 --- /dev/null +++ b/odemx-lite/examples/Example_Producer_LoggingManager.cpp @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Producer_LoggingManager.cpp + * @author Ronald Kluth + * @date created at 2009/12/28 + * @brief Example showing the use of a producer class with ODEMx's default logging + * @since 3.0 + */ + +/** + * @example Example_Producer_LoggingManager.cpp + * The usage of ODEMx default logging is shown. + * + * The LoggingManager is responsible for managing default logging components. + * A simple call to @c enableDefaultLogging suffices to activate it. The + * parameters can be STDOUT, XML, or DATABASE. The latter two would then + * require another string to specify the location. + */ + +#include "Example_Producer_StopWatch.h" + +int main() { + odemx::base::Simulation& sim = odemx::getDefaultSimulation(); + sim.enableDefaultLogging( odemx::data::output::STDOUT ); + + StopWatch watch( sim, "Stop Watch" ); + watch.start(); + sim.setCurrentTime( 10 ); + watch.stop(); + // + // Even though, logging is disbled for the watch object, it will still + // produce warning messages because the failure-related channels cannot + // be deactivated. + // + watch.disableLogging(); + watch.stop(); +} diff --git a/odemx-lite/examples/Example_Producer_StopWatch.h b/odemx-lite/examples/Example_Producer_StopWatch.h new file mode 100644 index 0000000000000000000000000000000000000000..1e64c90b29eba379ba3f90ceb75d19f36780f5ec --- /dev/null +++ b/odemx-lite/examples/Example_Producer_StopWatch.h @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Producer_StopWatch.h + * @author Ronald Kluth + * @date created at 2010/04/13 + * @brief Example showing the use of ODEMx log channels within a producer class + * @since 3.0 +*/ + +/** + * @example Example_Producer_StopWatch.h + * The typical usage of ODEMx logging is shown. + * + * Since most ODEMx components are derived from odemx::data::Producer, + * it is actually quite easy to use the log channels provided by that + * base class. This example shows the definition of a log producing + * class that makes use of the channels @c info and @c error. + */ + +#ifndef EXAMPLE_PRODUCER_STOPWATCH_H_ +#define EXAMPLE_PRODUCER_STOPWATCH_H_ + +#include <odemx/odemx.h> + +class StopWatch: public odemx::data::Producer { +public: + StopWatch( odemx::base::Simulation& sim, const odemx::data::Label& label ) + : Producer( sim, label ), running( false ) + {} + void start() { + running = true; + startTime = getSimulation().getTime(); + info << log( "started" ); + } + void stop() { + if( running ) { + running = false; + info << log( "stopped" ).detail( "duration", getDuration() ); + } else { + error << log( "StopWatch::stop(): stop watch is not running" ); + } + } + odemx::base::SimTime getDuration() { return getSimulation().getTime()-startTime; } +private: + bool running; + odemx::base::SimTime startTime; +}; + +#endif /* EXAMPLE_PRODUCER_STOPWATCH_H_ */ diff --git a/odemx-lite/examples/Example_ProtocolDevice.cpp b/odemx-lite/examples/Example_ProtocolDevice.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b994189d02afe9e8c4bfe780c5ff79d660c03467 --- /dev/null +++ b/odemx-lite/examples/Example_ProtocolDevice.cpp @@ -0,0 +1,239 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_ProtocolDevice.cpp + * @author Ronald Kluth + * @date created at 2010/04/02 + * @brief Example showing usage of the protocol simulation module + * @since 3.0 +*/ + +/** + * @example Example_ProtocolDevice.cpp + * This example shows the simple communication protocol XCS with highest detail. + * + * Class Node uses a protocol stack to communicate with another node. The stack + * is composed of an entity class in the upper layer and a device in the + * lower layer. The communication runs over a medium which connects the + * devices of network nodes. + */ + +#include <odemx/odemx.h> +#include <iostream> + +using namespace odemx; +using namespace odemx::protocol; +using std::static_pointer_cast; + +typedef Service::AddressType Addr; +typedef std::string SapName; +// +// PDU type used in the upper layer +// +struct StringData: Pdu +{ + typedef std::shared_ptr< StringData > Ptr; + Addr src, dest; + SapName destSap; + std::string data; + + StringData( const Addr& src, const Addr& dest, const SapName& dSap, + const std::string& data ) + : src( src ), dest( dest ), destSap( dSap ), data( data ) + {} + virtual PduPtr clone() const + { + return PduPtr( new StringData( src, dest, destSap , data ) ); + } + virtual std::size_t getSize() const + { + return src.size() + dest.size() + destSap.size() + data.size() ; + } +}; +// +// PDU type used in the lower layer +// +struct TransmissionData: Pdu +{ + Addr& src; + Addr& dest; + StringData::Ptr payload; + + TransmissionData( StringData::Ptr data ) + : src( data->src ), dest( data->dest ), payload( data ) + {} + virtual PduPtr clone() const + { + return PduPtr( new TransmissionData( payload ) ); + } + virtual std::size_t getSize() const + { + return payload->getSize(); + } +}; +// +// The entity of the upper layer, which transforms StringData into +// TransmissionData. +// +class XcsEntity: public Entity +{ +public: + XcsEntity( base::Simulation& sim, const data::Label& label ) + : Entity( sim, label ) + { + addSap( "XCSin" ); + addSap( "CSout" ); + } + virtual void handleInput( const std::string& sapName, PduPtr p ) + { + if( sapName == "XCSin" ) + { + StringData::Ptr pdu = static_pointer_cast< StringData >( p ); + info << log( "send" ); + send( "CSin", PduPtr( new TransmissionData( pdu ) ) ); + } + else if( sapName == "CSout" ) + { + StringData::Ptr pdu = static_pointer_cast< TransmissionData >( p )->payload; + info << log( "pass" ); + pass( pdu->destSap, pdu ); + } + } +}; +// +// Device class that sends data via the medium +// +class XcsDevice: public Device +{ +public: + typedef TransmissionData PduType; + + XcsDevice( base::Simulation& sim, const data::Label& label ) + : Device( sim, label ) + { + addSap( "CSin" ); + } + virtual void handleSend( const std::string& sap, PduPtr p ) + { + info << log( "send" ); + send( p ); + } + virtual void handleReceive( PduPtr p ) + { + info << log( "pass" ); + pass( "CSout", p ); + } + virtual base::SimTime computeTransmissionDuration( std::size_t pduSize ) + { + return static_cast< base::SimTime >( pduSize ); + } +}; +// +// Global medium +// +Medium medium( getDefaultSimulation(), "TransmissionMedium" ); +// +// A stack factory function that creates the stack's layers and registers +// service providers with them. The layers are then added to the stack +// in top-down order. +// +std::auto_ptr< Stack > makeStack( base::Simulation& sim, const data::Label& label, + const Addr& address ) +{ + Layer* entityLayer = new Layer( sim, label + " entity layer" ); + entityLayer->addServiceProvider( new XcsEntity( sim, label + " entity" ) ); + Layer* deviceLayer = new Layer( sim, label + " device layer" ); + Device* device = new XcsDevice( sim, label + " device" ); + deviceLayer->addServiceProvider( device ); + medium.registerDevice( address, *device ); + + std::auto_ptr< Stack > stack( new Stack( sim, label ) ); + stack->addLayer( entityLayer ); + stack->addLayer( deviceLayer ); + return stack; +} +// +// Node is a very simple process that can either be a sender or a receiver, +// depending on whether a reciever address is set. A stack is used to +// facilitate the communication between nodes. +// +class Node: public base::Process +{ +public: + Node( const data::Label& label, const Addr& addr, const Addr& recAddr = "" ) + : Process( getDefaultSimulation(), label ) + , stack_( makeStack( getSimulation(), getLabel(), addr ) ) + , address_( addr ) + , receiver_( recAddr ) + , isSender_( ! recAddr.empty() ) + { + stack_->addReceiveSap( "XCSout" ); + } + virtual int main() + { + if( isSender_ ) + { + Sap* sap = stack_->getSap( "XCSin" ); + StringData::Ptr pdu( new StringData( address_, receiver_, "XCSout", "message" ) ); + info << log( "sending PDU via XCSin" ) + .detail( "to", pdu->dest ) + .detail( "data", pdu->data ); + sap->write( pdu ); + } + else + { + Sap* sap = stack_->getReceiveSap( "XCSout" ); + while( true ) + { + StringData::Ptr pdu = std::static_pointer_cast< StringData >( sap->read() ); + info << log( "received PDU via XCSout" ) + .detail( "from", pdu->src ) + .detail( "data", pdu->data ); + } + } + return 0; + } +private: + std::auto_ptr< Stack > stack_; + Addr address_; + Addr receiver_; + bool isSender_; +}; + +//--------------------------------------------------------------------------main + +int main() +{ + base::Simulation& sim = getDefaultSimulation(); + sim.addConsumer( data::channel_id::info, + data::output::OStreamWriter::create( std::cout ) ); + + Node sender( "Sender", "Addr0", "Addr1" ); + Node receiver( "Receiver", "Addr1" ); + sender.activate(); + receiver.activate(); + // + // Connect the devices of the two nodes by their addresses. + // + medium.addLink( "Addr0", "Addr1", 0 ); + // + // Let the sender and receiver do their work. + // + sim.run(); +} diff --git a/odemx-lite/examples/Example_ProtocolEntity.cpp b/odemx-lite/examples/Example_ProtocolEntity.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9c705ce66b74f415ed88774e77d2bdfa2cd3899 --- /dev/null +++ b/odemx-lite/examples/Example_ProtocolEntity.cpp @@ -0,0 +1,230 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_ProtocolEntity.cpp + * @author Ronald Kluth + * @date created at 2010/04/02 + * @brief Example showing usage of the protocol simulation module + * @since 3.0 +*/ + +/** + * @example Example_ProtocolEntity.cpp + * This example shows the simple communication protocol XCS with medium detail. + * + * Class Node uses a protocol stack to communicate with another node. The stack + * is composed of an entity class in the upper layer and a device in the + * lower layer. The communication runs directly between the connected service + * objects. + */ + +#include <odemx/odemx.h> +#include <iostream> + +using namespace odemx; +using namespace odemx::protocol; +using std::static_pointer_cast; + +typedef Service::AddressType Addr; +typedef std::string SapName; +// +// PDU type used in the upper layer +// +struct StringData: Pdu +{ + typedef std::shared_ptr< StringData > Ptr; + Addr src, dest; + SapName destSap; + std::string data; + + StringData( const Addr& src, const Addr& dest, const SapName& dSap, + const std::string& data ) + : src( src ), dest( dest ), destSap( dSap ), data( data ) + {} + virtual PduPtr clone() const + { + return PduPtr( new StringData( src, dest, destSap , data ) ); + } + virtual std::size_t getSize() const + { + return src.size() + dest.size() + destSap.size() + data.size() ; + } +}; +// +// PDU type used in the lower layer +// +struct TransmissionData: Pdu +{ + Addr& src; + Addr& dest; + StringData::Ptr payload; + + TransmissionData( StringData::Ptr data ) + : src( data->src ), dest( data->dest ), payload( data ) + {} + virtual PduPtr clone() const + { + return PduPtr( new TransmissionData( payload ) ); + } + virtual std::size_t getSize() const + { + return payload->getSize(); + } +}; +// +// The entity of the upper layer, which transforms StringData into +// TransmissionData. +// +class XcsEntity: public Entity +{ +public: + XcsEntity( base::Simulation& sim, const data::Label& label ) + : Entity( sim, label ) + { + addSap( "XCSin" ); + addSap( "CSout" ); + } + virtual void handleInput( const std::string& sapName, PduPtr p ) + { + if( sapName == "XCSin" ) + { + info << log( "send" ); + StringData::Ptr pdu = static_pointer_cast< StringData >( p ); + send( "CSin", PduPtr( new TransmissionData( pdu ) ) ); + } + else if( sapName == "CSout" ) + { + info << log( "pass" ); + StringData::Ptr pdu = static_pointer_cast< TransmissionData >( p )->payload; + pass( pdu->destSap, pdu ); + } + } +}; +// +// Service implementation that transmits data directly to its peers. +// +class XcsService: public Service +{ +public: + typedef TransmissionData PduType; + + XcsService( base::Simulation& sim, const data::Label& label ) + : Service( sim, label ) + { + addSap( "CSin" ); + } + virtual void handleSend( const std::string& sap, PduPtr p ) + { + info << log( "send" ); + holdFor( p->getSize() ); + send( std::static_pointer_cast< PduType >( p )->dest, p ); + } + virtual void handleReceive( PduPtr p ) + { + info << log( "pass" ); + pass( "CSout", p ); + } +}; +// +// A stack factory function that creates the stack's layers and registers +// service providers with them. The layers are then added to the stack +// in top-down order. +// +std::auto_ptr< Stack > makeStack( base::Simulation& sim, const data::Label& label, + const Addr& address ) +{ + Layer* entityLayer = new Layer( sim, label + " entity layer" ); + entityLayer->addServiceProvider( new XcsEntity( sim, label + " entity" ) ); + Layer* serviceLayer = new Layer( sim, label + " service layer" ); + Service* service = new XcsService( sim, label + " service" ); + serviceLayer->addServiceProvider( service ); + XcsService::registerService( address, *service ); + + std::auto_ptr< Stack > stack( new Stack( sim, label ) ); + stack->addLayer( entityLayer ); + stack->addLayer( serviceLayer ); + return stack; +} +// +// Node is a very simple process that can either be a sender or a receiver, +// depending on whether a reciever address is set. A stack is used to +// facilitate the communication between nodes. +// +class Node: public base::Process +{ +public: + Node( const data::Label& label, const Addr& addr, const Addr& recAddr = "" ) + : Process( getDefaultSimulation(), label ) + , stack_( makeStack( getSimulation(), getLabel(), addr ) ) + , address_( addr ) + , receiver_( recAddr ) + , isSender_( ! recAddr.empty() ) + { + stack_->addReceiveSap( "XCSout" ); + } + virtual int main() + { + if( isSender_ ) + { + Sap* sap = stack_->getSap( "XCSin" ); + StringData::Ptr pdu( new StringData( address_, receiver_, "XCSout", "message" ) ); + info << log( "sending PDU via XCSin" ) + .detail( "to", pdu->dest ) + .detail( "data", pdu->data ); + sap->write( pdu ); + } + else + { + Sap* sap = stack_->getReceiveSap( "XCSout" ); + while( true ) + { + StringData::Ptr pdu = std::static_pointer_cast< StringData >( sap->read() ); + info << log( "received PDU via XCSout" ) + .detail( "from", pdu->src ) + .detail( "data", pdu->data ); + } + } + return 0; + } +private: + std::auto_ptr< Stack > stack_; + Addr address_; + Addr receiver_; + bool isSender_; +}; + +//--------------------------------------------------------------------------main + +int main() +{ + base::Simulation& sim = getDefaultSimulation(); + sim.addConsumer( data::channel_id::info, + data::output::OStreamWriter::create( std::cout ) ); + + Node sender( "Sender", "Addr0", "Addr1" ); + Node receiver( "Receiver", "Addr1" ); + // + // Since the service objects of both nodes' stacks are connected + // upon construction, the sending of data will work automatically. + // No links need be set. + // + sender.activate(); + receiver.activate(); + sim.run(); +} diff --git a/odemx-lite/examples/Example_ProtocolService.cpp b/odemx-lite/examples/Example_ProtocolService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d990e5139b56d606c77af8ef6f6085cd26eb48c --- /dev/null +++ b/odemx-lite/examples/Example_ProtocolService.cpp @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_ProtocolService.cpp + * @author Ronald Kluth + * @date created at 2010/04/01 + * @brief Example showing usage of the protocol simulation module + * @since 3.0 +*/ + +/** + * @example Example_ProtocolService.cpp + * This example shows the simple communication protocol XCS with lowest detail. + * + * Class Node uses a simple service implementation to communicate with + * another node. We abstract from the stack as well as the network topology. + * The communication runs directly between the connected service + * objects. + */ + +#include <odemx/odemx.h> +#include <iostream> + +using namespace odemx; +using namespace odemx::protocol; +using std::static_pointer_cast; + +typedef Service::AddressType Addr; +typedef std::string SapName; +// +// PDU type used for data transfer between nodes +// +struct StringData: Pdu +{ + typedef std::shared_ptr< StringData > Ptr; + Addr src, dest; + SapName destSap; + std::string data; + + StringData( const Addr& src, const Addr& dest, const SapName& dSap, + const std::string& data ) + : src( src ), dest( dest ), destSap( dSap ), data( data ) + {} + virtual PduPtr clone() const + { + return PduPtr( new StringData( src, dest, destSap , data ) ); + } + virtual std::size_t getSize() const + { + return src.size() + dest.size() + destSap.size() + data.size() ; + } +}; +// +// Simple service implementation that waits before sending the data in +// order to model a transmission duration. +// +class XcsService: public Service +{ +public: + typedef StringData PduType; + + XcsService( base::Simulation& sim, const data::Label& label ) + : Service( sim, label ) + { + addSap( "XCSin" ); + } + virtual void handleSend( const std::string& sap, PduPtr p ) + { + info << log( "send" ); + holdFor( p->getSize() ); + send( static_pointer_cast< PduType >( p )->dest, p ); + } + virtual void handleReceive( PduPtr p ) + { + info << log( "pass" ); + pass( static_pointer_cast< PduType >( p )->destSap, p ); + } +}; +// +// Node is a very simple process that can either be a sender or a receiver, +// depending on whether a receiver address is set. In the simplest form, a +// service object is used to facilitate the communication between nodes. +// +class Node: public base::Process +{ +public: + Node( const data::Label& label, const Addr& addr, const Addr& recAddr = "" ) + : Process( getDefaultSimulation(), label ) + , service_( getSimulation(), label + " service" ) + , address_( addr ) + , receiver_( recAddr ) + , isSender_( ! recAddr.empty() ) + { + service_.addReceiveSap( "XCSout" ); + XcsService::registerService( addr, service_ ); + } + virtual int main() + { + if( isSender_ ) + { + Sap* sap = service_.getSap( "XCSin" ); + StringData::Ptr pdu( new StringData( address_, receiver_, "XCSout", "message" ) ); + info << log( "sending PDU via XCSin" ) + .detail( "to", pdu->dest ) + .detail( "data", pdu->data ); + sap->write( pdu ); + } + else + { + Sap* sap = service_.getReceiveSap( "XCSout" ); + while( true ) + { + StringData::Ptr pdu = static_pointer_cast< StringData >( sap->read() ); + info << log( "received PDU via XCSout" ) + .detail( "from", pdu->src ) + .detail( "data", pdu->data ); + } + } + return 0; + } +private: + XcsService service_; + Addr address_; + Addr receiver_; + bool isSender_; +}; + +//--------------------------------------------------------------------------main + +int main() +{ + base::Simulation& sim = getDefaultSimulation(); + sim.addConsumer( data::channel_id::info, + data::output::OStreamWriter::create( std::cout ) ); + + Node sender( "Sender", "Addr0", "Addr1" ); + Node receiver( "Receiver", "Addr1" ); + // + // Since registered service objects are connected automaticallly, + // the sending of data will work automatically. No links need be set. + // + sender.activate(); + receiver.activate(); + sim.run(); +} diff --git a/odemx-lite/examples/Example_Res.cpp b/odemx-lite/examples/Example_Res.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c02fd7959bef8973edcb1133f896492896d14a0 --- /dev/null +++ b/odemx-lite/examples/Example_Res.cpp @@ -0,0 +1,291 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Res.cpp + * @author Ronald Kluth + * @date created at 2009/02/11 + * @brief Example for basic simulation techniques using a limited resource + * @since 3.0 + */ + +/** + * @example Example_Res.cpp + * + * This example shows the basic techniques for simulating a limited resource + * with ODEMx. The class with the limited resource is a gas station with only + * two gas pumps. + * + * Cars are generated by a self-scheduling event until its counter reaches 0. + * When the car processes are activated, they enter the gas station and thereby + * try to acquire a resource - one of the pumps. If both pumps are in use, they + * will automatically wait their turn in a queue provided by an odemx::synchronization::Res + * object. + */ + +#include <odemx/odemx.h> + +#include <iostream> +#include <vector> +//#include <cstdlib> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + + +// short namespace alias +namespace Rand = odemx::random; + +// forward declarations +class Car; +odemx::base::SimTime getRandomTime( Rand::ContinuousDist& dist ); + +//--------------------------------------------------------------------GasStation +// +// This passive class models a very simple gas station that only has two pumps +// and no other attributes. The pumps are represented by a Res object with two +// initial tokens and a maximum token limit of two. +// +class GasStation +{ +public: + typedef std::shared_ptr< GasStation > Ptr; + + GasStation(): gasPumps_( odemx::getDefaultSimulation(), "Gas Pumps", 2, 2 ) {} + void enter(); + void leave(); +private: + odemx::synchronization::Res gasPumps_; +}; + +//---------------------------------------------------------------------------Car +// +// Cars are modeled as very simple processes that do nothing else but enter +// the station and leave it once they have been refueled. The only attributes +// of this class are a reference to the gas station it uses and another +// reference to a random number generator for randomized refuel periods. +// +class Car: public odemx::base::Process +{ +public: + typedef std::shared_ptr< Car > Ptr; + + Car( GasStation& station, Rand::ContinuousDist& refuelTime ) + : Process( odemx::getDefaultSimulation(), "Car" ) + , station_( station ) + , refuelTime_( refuelTime ) + {} + virtual int main(); + void refuel(); +private: + GasStation& station_; + Rand::ContinuousDist& refuelTime_; +}; + +//-----------------------------------------------------------------------Arrival +// +// This event class describes the arrival of a new car. It is a generator for +// new cars, which are activated (scheduled) right after the event action is +// finished. The number of cars to be generated is set in the constructor. +// This class also provides memory management by using a vector to keep track +// of all cars it creates. +// +class Arrival: public odemx::base::Event +{ +public: + typedef std::shared_ptr< Arrival > Ptr; + + Arrival( GasStation& station, unsigned int count, + Rand::ContinuousDist& arrivalTime, + Rand::ContinuousDist& refuelTime ) + : Event( odemx::getDefaultSimulation(), "Car Arrival Event" ) + , station_( station ) + , count_( count ) + , arrivalTime_( arrivalTime ) + , refuelTime_( refuelTime ) + {} + virtual void eventAction(); + void scheduleAtRandomTime(); +private: + GasStation& station_; + unsigned int count_; + Rand::ContinuousDist& arrivalTime_; + Rand::ContinuousDist& refuelTime_; + // automatic memory management + std::vector< Car::Ptr > generatedCars_; +}; + +//------------------------------------------------------------method definitions +// +// Entering the gas station is modeled by acquiring a resource (a gas pump). +// If none is available, the caller's execution will automatically be blocked +// and it will be inserted into a queue to wait its turn. +// +void GasStation::enter() +{ + gasPumps_.acquire( 1 ); +} +// +// Leaving the gas station is modeled by the release of an acquired resource. +// +void GasStation::leave() +{ + gasPumps_.release( 1 ); +} +// +// The car's described behavior only covers the entering and leaving of the +// gas station. If it cannot be serviced right away, the call to enter() will +// block the execution of main(). Once it was allowed to enter, the car can be +// refueled. After waiting for a random amount of refueling time, the car leaves +// the gas station. +// +int Car::main() +{ + info << log( "is entering the station" ); + station_.enter(); + info << log( "is refueling" ); + holdFor( getRandomTime( refuelTime_ ) ); + station_.leave(); + info << log( "has left the station" ); + return 0; +} +// +// The action associated with an arrival event is the creation and activation +// of a new car. After that, the event object reschedules itself after a random +// period of time. +// +void Arrival::eventAction() +{ + Car::Ptr car( new Car( station_, refuelTime_ ) ); + car->activate(); + info << log( "activated car" ).detail( "name", car->getLabel() ); + generatedCars_.push_back( car ); + + if( count_ > 0 ) + { + --count_; + this->scheduleIn( getRandomTime( arrivalTime_ ) ); + } +} + +//--------------------------------------------------------------------------main + +int main( int argc, char* argv[] ) +{ + using namespace odemx; + using namespace odemx::data::output; + using odemx::base::Simulation; + // + // Check command line arguments: we require a number for gas stations. + // + if( argc != 2 ) + { + std::cerr << "Usage: " << argv[0] << " <station count>" << std::endl; + return -1; + } + // + // Get the station count and check for error. + // + int stationCount = std::atoi( argv[1] ); + if( stationCount < 1 ) + { + std::cerr << "Error: station count < 1" << std::endl; + } + // + // In our class definitions, we have only used Process and Event + // constructors without a Simulation parameter, thereby using the + // default simulation context. Here, we get a reference to it. + // + Simulation& sim = getDefaultSimulation(); + // + // Every simulation run should be characterized by a description of the + // goals to be achieved. + // + sim.setDescription( "Simulation of a basic limited resource." ); + // + // The simulation context can handle logging automatically and will use + // sensible defaults. All log records will be logged to a rotating + // XML file writer, while warnings and errors are also sent to stderr. + // Furthermore, all statistical records will be computed and buffered + // internally. A call to reportStatistics() will create an XML report. + // + sim.enableDefaultLogging( STDOUT ); + // + // Only after setting log data consumers to the channels will log records + // be visible. We initialize all other simulation elements after calling + // enableDefaultLogging() to make sure we capture all log data. + // + // We use two random number generators for random time periods. One + // influences the arrival frequency of new cars, and the other is used for + // random refueling periods. + // + Rand::Normal randomArrival( sim, "Arrival Time", 5, 2 ); + Rand::Normal randomRefueling( sim, "Refueling Time", 10, 5 ); + // + // Create the needed objects: a number of gas stations, and the + // corresponding car generators. (We use vectors with shared pointers to + // objects for automatic memory management.) + // + std::vector< Arrival::Ptr > arrivalEvents; + std::vector< GasStation::Ptr > stations; + do + { + GasStation::Ptr newStation( new GasStation() ); + + Arrival::Ptr newCarGenerator( + new Arrival( *newStation, 10, randomArrival, randomRefueling ) ); + // + // Schedule the car generator for its initial execution. + // + newCarGenerator->scheduleIn( getRandomTime( randomArrival ) ); + + stations.push_back( newStation ); + arrivalEvents.push_back( newCarGenerator ); + } + while( --stationCount ); + // + // Start the simulation and let it run until the schedule is empty. + // + sim.run(); + // + // Output a statistics report computed from the default log. In this case, + // it will contain usage data about the random number generators, the + // resource objects (gas pumps) and their internal queues. + // + sim.reportDefaultStatistics( STDOUT ); + sim.reportDefaultStatistics( XML, "basicResourceStatistics.xml" ); + return 0; +} +// +// Since random number generators sometimes also generate negative values, +// we cannot simply use samples as time values. This helper function ensures +// that only values greater than or equal to zero are returned. +// +odemx::base::SimTime getRandomTime( Rand::ContinuousDist& dist ) +{ + odemx::base::SimTime retVal; + do + { + retVal = (odemx::base::SimTime) dist.sample(); + } + while( retVal <= 0 ); + + return retVal; +} diff --git a/odemx-lite/examples/Example_Shop.cpp b/odemx-lite/examples/Example_Shop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..482542504bd118c7e68a2b51081f6c0c6ceb15ca --- /dev/null +++ b/odemx-lite/examples/Example_Shop.cpp @@ -0,0 +1,872 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Example_Shop.cpp + + \author Ralf Gerstenberger + + \date created at 2003/07/15 + + \brief Shop example with ODEMx + + This example shows more advanced techniques to + realize a process simulation with ODEMx. + +\since 1.0 +*/ +/** \example Example_Shop.cpp + In this example, a shop which is selling different + goods to customers is simulated. Shop-assistants handle + the final payment after a customer has gathered their + goods from the shelves in the shop. Each shelf is + holding a limited amount of one commodity. If a shelf + runs out of its commodity, a shop-assistant has to + restock the shelf. There is also a shopkeeper, who + employs the shop-assistants and orders goods, if the + store room of the shop is running out of any. Finally, + there is a process generating new customers after a + random delay. +*/ + +// +// Includes +// +// We include the main ODEMx header file odemx.h which in +// turn includes the other header files of ODEMx. All +// header files of ODEMx define a macro when included, +// to prevent repetitive inclusion. That means it doesn't +// hurt to include a header file more than once, because +// subsequent inclusions are ignored. +// +#include <odemx/odemx.h> +// +// Apart from ODEMx we use some C++ standard features in +// this simulation. +// +#include <iostream> +#include <fstream> +#include <list> +#include <string> +#include <vector> + +// +// Namespaces +// +// All ODEMx classes reside in a sub-namespace of namespace odemx +// to prevent naming conflicts. In this simulation it is safe to +// import several odemx namespaces into the global namespace. +// +using namespace odemx::base; +using namespace odemx::data; +using namespace odemx::data::output; +using namespace odemx::random; +using namespace odemx::synchronization; +using namespace std; + +// +// Global parameters +// +// To simplify matters we use global parameters in this example. +// That is, however, not recommended in general. A better place +// for simulation parameters is the specific simulation class. +// +// GOODS contains the different commodities sold in the shop. +// +static const string GOODS[] = {"Apple", "Bananas", "Bread", "Butter", "Candies", + "Cheese", "Chips", "Chocolate", "Mixed-pickles", "Fish", + "Jam", "Juice", "Lemon", "Lemonade", "Marmalade", + "Milk", "Orange", "Pepper", "Pineapples", "Pork", + "Salami", "Salt", "Sugar", "Tomatoes", "Water"}; + +// +// NUMBER_OF_GOODS is used in many for-loops as the end-condition. +// +static const int NUMBER_OF_GOODS = 25; + +// +// INIT_STOCK is the initial amount of each good held in the +// store room. +// +static const int INIT_STOCK = 50; + +// +// INIT_TILLS is the initial number of tills available. +// +static const int INIT_TILLS = 5; + +// +// INIT_PERSONNEL is the initial number of shop-assistants +// employed by the shopkeeper. +// +static const int INIT_PERSONNEL = 8; + +// +// SHELF_CAPACITY defines the capacity of a shelf. The capacity +// is measured in items, not in size. That means every shelf +// holds up to SHELF_CAPACITY items of its commodity. +// +static const int SHELF_CAPACITY = 15; + +// +// ACCEPTED_QUEUE_LENGTH defines the queue length after +// which a shop-assistant will help out at the tills. +// +static const int ACCEPTED_QUEUE_LENGTH = 5; + +// +// ACCEPTED_SHELF_STOCK defines the number of items in +// a shelf after which the shelf has to be refilled. +// +static const int ACCEPTED_SHELF_STOCK = 5; + +// +// The following parameters define delays for payment, +// for refilling shelves, for taking goods from a shelf, for moving +// between shelves, and they define the time after which the shopkeeper +// is checking the store room of the shop again. +// +static const SimTime PAYMENT_DELAY = 5; +static const SimTime RESTOCK_DELAY = 15; +static const SimTime TAKE_DELAY = 1; +static const SimTime MOVE_DELAY = 1; +static const SimTime STOCKKEEPER_DELAY = 60; + +// +// Pre-declarations +// +class Shelf; +class Tills; +class Shopkeeper; +class Assistant; +class Customer; +class CustomerGen; + +// +// Classes +// + +// +// The class ShopSim is derived from Simulation and provides +// access to some important objects of this simulation. All +// classes which have a pointer to ShopSim can use the get* +// methods to get these objects. In addition we could move +// the global parameters to this class. ShopSim also +// does some initializations in its constructor and the +// initSimulation() function. +// +class ShopSim : public Simulation +{ + // Shelves in the shop, one for each commodity + vector<Shelf*> shelves; + // Back-store for refilling shelves + vector<int> stock; + // Customers pay at one of the tills + Tills* tills; + + Shopkeeper* boss; + CustomerGen* generator; + + // Random number generators + RandomInt *rng5, *rng10, *rng; + NegativeExponential* delay; + + // Assistant-management + CondQ* work; + +public: + // Construction and initialisation + ShopSim(); + virtual void initSimulation(); + + // get*() methods + vector<Shelf*>& getShelves() {return shelves;} + vector<int>& getStock() {return stock;} + Tills* getTills() {return tills;} + + Shopkeeper* getBoss() {return boss;} + CustomerGen* getCustomerGen() {return generator;} + + DiscreteDist* getRNG() {return rng;} + DiscreteDist* getRNG5() {return rng5;} + DiscreteDist* getRNG10() {return rng10;} + ContinuousDist* getDelay() {return delay;} + + CondQ* getWork() {return work;} +}; + +// +// Shelf represents a shelf in our shop. Every shelf +// contains one commodity and provides methods for +// customers to take goods. The shop-assistants refill +// a shelf if its running out of stock. +// The management of commodity items held in a shelf +// is realised with the ODEMx standard component Res. +// +class Shelf +{ + // Pointer to ShopSim + ShopSim* sim; + + // The type of commodity presented in this shelf + int type; + + // The amount of goods left in this shelf + Res commodity; + +public: + // Construction + Shelf(ShopSim* s, int t); + + // Type of commodity presented in this shelf + int getType() const {return type;} + + // Customers use this method to take goods. + int takeCommodity(int n); + + // Assistants use this method to restock the shelf. + int fillShelf(int n); + + // Assistants use this method to check the stock. + int checkStock() const {return commodity.getTokenNumber();} +}; + +// +// After taking their goods, customers go to the tills +// to pay. There are several tills available but a till +// also needs to be handled by a shop-assistant to be active. +// The payment is managed with the ODEMx standard component +// WaitQ which realizes the synchronization between customers +// giving the money and shop-assistants taking it. The Tills +// also collect statistic data about the number of assistants +// by using the ODEMx class Accum. +// +class Tills +{ + // Pointer to ShopSim + ShopSim* sim; + + // Customers wait in a WaitQ for service. + WaitQ queue; + + // Tills keep statistics about the assistants. + odemx::statistics::Accumulate* statistic; + + // The number of assistants handling the tills. + int cashier; + + // The number of tills available. + int tills; + +public: + // Construction + Tills(ShopSim* s); + + // Customers use the method pay() to enter the queue (enqueue) at the + // tills and to pay. + void pay(); + + // Assistants use take to get the next customer. + Customer* take(); + + // The number of shop-assistants who take the payment changes, + // updated with updateCashier(). + void updateCashier(int n); + + // get* methods + int getQueueLength() const {return queue.getWaitingSlaves().size();} + int getCashier() const {return cashier;} + int getTills() const {return tills;} +}; + +// +// The shopkeeper is responsible for the employment of shop-assistants +// and the ordering of goods. The class Shopkeeper is derived from +// Process and defines the behaviour of the shopkeeper by implementing +// the function main(). +// +class Shopkeeper : public Process +{ +public: + // Construction + Shopkeeper(ShopSim& sim); + + // Behaviour + virtual int main(); +}; + +// +// Shop-assistants represent the work-force driving the shop. They +// refill the shelves or handle a till. The class Assistant defines +// the behavior of the shop assistants by implementing main(). +// Shop assistants decide on their own which task they fulfil +// next (handle a till or refill shelves). If neither is required +// they wait for work in a conditional queue provided by ODEMx and +// kept in the ShopSim class (ShopSim::work). +// +class Assistant : public Process +{ +public: + // Construction + Assistant(ShopSim& sim); + + // Behaviour + virtual int main(); + + // chooseWork and work are used to find the next task for an + // assistant or to wait for work. + int chooseWork(); + bool work(); +}; + +// +// This class represents the customers in this simulation. +// Customers have (random) demand which they try to fulfil +// by taking goods from the shelves. Finally, a customer pays +// for the taken goods at the tills. +// +class Customer : public Process +{ + // The customer's demand. + vector<int> demand; + + // The goods in the customer's basket. + vector<int> basket; + +public: + // Construction + Customer(ShopSim& sim); + + // Behaviour + virtual int main(); +}; + +// +// The Customers are randomly created by CustomerGen. By this means +// we achieve an approximation of the customer-flow in our shop. +// +class CustomerGen : public Process +{ +public: + // Construction + CustomerGen(ShopSim& sim); + + // Behaviour + virtual int main(); +}; + +// +// Implementations of member functions +// + +// +// Construction of a ShopSim object itself and some other major +// objects. +// +ShopSim::ShopSim() : + Simulation("ShopSim"), + shelves(NUMBER_OF_GOODS), + stock(NUMBER_OF_GOODS) +{ + // Create and initialise shelves, one shelf for each commodity. + for (int i=0; i<NUMBER_OF_GOODS; ++i) + { + shelves[i] = new Shelf(this, i); + stock[i] = INIT_STOCK; + } + + // Create the tills, the boss, and the customer generator. + tills = new Tills(this); + boss = new Shopkeeper(*this); + generator = new CustomerGen(*this); + + // Create the random number generators. + // RandomInt and NegativeExponential are provided by ODEMx. + rng = new RandomInt(*this, "RNG", 0, NUMBER_OF_GOODS -1); + rng5 = new RandomInt(*this, "RNG", 0, 5); + rng10 = new RandomInt(*this, "RNG", 0, 10); + delay = new NegativeExponential(*this, "Delay", 0.125); + + // Finally, the CondQ work is created and added to the report. + work = new CondQ(*this, "Work"); +} + +// +// initSimulation is called before the simulation starts. We +// use this function to activate the boss and the customer +// generator. They in turn create the other processes. +// The initSimulation function is sort of an entry-point +// of a simulation. It is called before the simulation +// starts and is the best place to activate the first processes +// of a simulation. +// +void ShopSim::initSimulation() +{ + boss->activate(); + generator->activate(); +} + +// +// Construction of a Shelf object. +// +Shelf::Shelf(ShopSim* s, int t) : + sim(s), + type(t), + commodity(*s, ("Shelf_" + GOODS[t]), 0, SHELF_CAPACITY) +{ + // Shelf is using a Res object to manage the amount of goods + // available. Res is providing some report about its usage. +} + +// +// fillShelf is used by the shop-assistants to restock the shelf. +// In this version the function is only a wrapper to the release +// method of the Res object which is actually managing the available +// goods. +// +int Shelf::fillShelf(int n) +{ + commodity.release(n); + return commodity.getTokenNumber(); +} + +// +// takeCommodity is used by the customers to get the goods. We +// could just relay the call to commodity.acquire(). But then a +// customer would wait until there are enough items available. +// Instead we signal the shop-assistants the need to refill a +// shelf and give the customer only the items available. +// +int Shelf::takeCommodity(int n) +{ + int avail = commodity.getTokenNumber(); + + if (avail > n) + { + commodity.acquire(n); + return n; + } + else + { + commodity.acquire(avail); + sim->getWork()->signal(); + return avail; + } +} + +// +// Construction of the Tills object. +// +Tills::Tills(ShopSim* s) : + sim(s), + queue(*s, "Tills queue"), + cashier(0), + tills(INIT_TILLS) +{ + // Tills is providing some additional statistics about + // the number of assistants handling the tills. + statistic = new odemx::statistics::Accumulate( *sim, "Tills statistics"); +} + +// +// Payment is done by the functions pay and take. There are +// two objects working together to handle payment. A customer +// giving the money and a shop-assistant taking it. Both have to +// be synchronised. Tills uses the standard ODEMx synchronisation +// object WaitQ to do this. +// +void Tills::pay() +{ + // Every time a customer wants to pay, waiting assistants + // are signaled. + sim->getWork()->signal(); + + // The synchronisation between a customer (who wants + // to pay) and an assistant is realised with WaitQ. WaitQ + // manages not only the synchronisation but also provides + // statistics. The wait() function used here adds the + // current process (the one that has just called pay()) to the + // queue. + queue.wait(); +} + +// +// Assistants use take to get the next customer. +// +Customer* Tills::take() +{ + Process* p = 0; + + // The coopt() function of WaitQ returns the next Customer + // in the queue(sorted according to priority and time of arrival). + // If there is no customer left the current process + // (the one that has just called take()) waits. + p = queue.coopt(); + + return (Customer*) p; +} + +// +// The number of assistants working at the tills is updated +// with this function. In this function the statistic about +// assistants handling tills is also updated. +// +void Tills::updateCashier(int n) +{ + cashier += n; + statistic->update(sim->getTime(), cashier); +} + +// +// Construction of Assistant objects. +// +Assistant::Assistant(ShopSim& sim) : + Process(sim, "Assistant") +{} + +// +// Assistant is derived from Process. That means it has to +// provide its own main() function, where it defines the actions +// done by an Assistant. +// +int Assistant::main() +{ + // + // At first we cache pointers to our simulation + // and to the tills. + // + ShopSim& sim = dynamic_cast< ShopSim& >( getSimulation() ); + Tills* tills = sim.getTills(); + + while (true) + { + // + // Wait for something to do: + // Assistants have to do two different tasks. + // If required they handle a till to collect + // payment from the customers. Otherwise they go + // through the shop and refill empty shelves. + // If neither is required they wait for work. + // ShopSim uses the ODEMx synchronisation object + // CondQ to keep track of waiting Assistants. + // CondQ allows processes to wait for certain + // conditions defined by a condition call-back + // function. Assistant's member function work() + // was designed to define the condition when an + // Assistant has to act. + // The first real action of an assistant is to + // wait for a task. + // + sim.getWork()->wait([&](Process* self) { + return static_cast<Assistant*>(self)->work(); + }); + + // + // Choose your work: + // The function chooseWork() determines what has + // to be done. It returns 1 if an assistant is + // needed at the tills and 2 if a shelf has to be + // refilled. + if (chooseWork()==1) + { + // + // Cashier task + // + + // update number of assistants at the tills + tills->updateCashier(1); + + // serve customers as long as there are any + while (tills->getQueueLength()>0) + { + // get the next customer in queue + Customer* c = tills->take(); + + // payment does take some time + holdFor(PAYMENT_DELAY); + + // finally, activate the customer + // to let them leave the store + c->activate(); + } + + // update number of assistants at the tills + tills->updateCashier(-1); + } + else + { + // + // Restock task + // + + // The assistant goes through all shelves and + // refills if necessary and possible. + vector<Shelf*>::iterator i; + for (i=sim.getShelves().begin(); i!=sim.getShelves().end(); ++i) + { + // We cache some pointer. + Shelf* shelf = *i; + vector<int>& stock = sim.getStock(); + int type = shelf->getType(); + + if (shelf->checkStock() < ACCEPTED_SHELF_STOCK && + stock[type] > 0) + { + // A shelf is filled up to its capacity + // if possible. + int n = SHELF_CAPACITY - shelf->checkStock(); + if (stock[type] < n) + n = stock[type]; + + shelf->fillShelf(n); + stock[type] -= n; + + // refilling takes time + holdFor(RESTOCK_DELAY); + } + } + } + } + + // This one will never be reached. + return 0; +} + +// +// chooseWork() decides which task should be done. +// +int Assistant::chooseWork() +{ + ShopSim& sim = dynamic_cast< ShopSim& >( getSimulation() ); + vector<Shelf*>::iterator i; + + // If the queue at the tills has exceeded an acceptable + // length and we have a free till without an assistant, + // the assistant should work at it. + if (sim.getTills()->getQueueLength() >= ACCEPTED_QUEUE_LENGTH && + sim.getTills()->getCashier() < sim.getTills()->getTills()) + return 1; + + // Otherwise, if there is a shelf out of stock while we have + // still goods left, the assistant should go on the refill-route. + for (i=sim.getShelves().begin(); i!=sim.getShelves().end(); ++i) + { + if ((*i)->checkStock()<ACCEPTED_SHELF_STOCK && + (sim.getStock())[(*i)->getType()] > 0) + return 2; + } + + // If neither is required the assistant should wait. + return 0; +} + +// +// The condition call-back work() uses the function chooseWork() +// to find something to do. +// +bool Assistant::work() +{ + return chooseWork()!=0; +} + +// +// Construction of the Shopkeeper object. +// +Shopkeeper::Shopkeeper(ShopSim& sim) : + Process(sim, "Shopkeeper") +{} + +// +// Like Assistant Shopkeeper is a Process and has to +// define its behaviour in the main() function. +// +int Shopkeeper::main() +{ + ShopSim& sim = dynamic_cast< ShopSim& >( getSimulation() ); + + // + // The first task of the shopkeeper is to employ + // some shop-assistants. + // + int i; + for (i=0; i<INIT_PERSONNEL; ++i) + { + Assistant* person = new Assistant(sim); + person->activate(); + } + + // + // Afterwards the only thing the shopkeeper has to do + // is to look after the stock of goods in his shop. + // + while (true) + { + // + // Order goods: + // We check all goods; if something runs out + // we fill it up again. + // + vector<int>& stock = sim.getStock(); + for (i=0; i<NUMBER_OF_GOODS; ++i) + { + if (stock[i]==0) stock[i]=INIT_STOCK; + } + + // + // Wait some time + // + holdFor(STOCKKEEPER_DELAY); + } + + return 0; +} + +// +// Construction of the Customer objects. +// +Customer::Customer(ShopSim& sim) : + Process(sim , "Customer"), + demand(NUMBER_OF_GOODS), + basket(NUMBER_OF_GOODS) +{} + +// +// The Customer wants a random amount of a random number of +// commodities. The customer tries to take the desired items +// from the shelves, pays at the tills, and finally, leaves the +// simulation. +// +int Customer::main() +{ + // We cache some pointer. + ShopSim& sim = dynamic_cast< ShopSim& >( getSimulation() ); + vector<Shelf*>& shelves = sim.getShelves(); + Tills* tills = sim.getTills(); + DiscreteDist* rng = sim.getRNG(); + DiscreteDist* rng5 = sim.getRNG5(); + DiscreteDist* rng10 = sim.getRNG10(); + + // + // Init wish-list + // + int i; + + // A customer wants up to 10 different types of goods. + int numberOfItems = rng10->sample(); + for (i=0; i<numberOfItems; ++i) + { + int type = rng->sample(); + int amount = rng5->sample(); + + demand[type] = amount; + } + + // + // Get goods from shelves + // + for (i=0; i<NUMBER_OF_GOODS; ++i) + { + if (demand[i]==0) + { + holdFor(MOVE_DELAY); + continue; + } + + Shelf* shelf = shelves[i]; + basket[i] = shelf->takeCommodity(demand[i]); + + holdFor(TAKE_DELAY + MOVE_DELAY); + } + + // + // Pay at a till + // + tills->pay(); + + return 0; +} + +// +// Construction of the CustomerGen object. +// +CustomerGen::CustomerGen(ShopSim& sim) : + Process(sim, "CustomerGen") +{} + +// +// CustomerGen creates Customers. +// +int CustomerGen::main() +{ + // Cash the ShopSim pointers. + ShopSim& sim = dynamic_cast< ShopSim& >( getSimulation() ); + Customer* c = 0; + SimTime delay; + + while (true) + { + // Create and activate a new Customer. + c = new Customer(sim); + c->activate(); + + // Wait a random time and update statistic. + delay = static_cast< SimTime >( sim.getDelay()->sample() ); + holdFor(delay); + } + + return 0; +} + +// +// Main: +// In the global main() function we finally create an object +// of the type ShopSim, start the trace, run the simulation for +// two simulated days, stop trace and generate the report. +// +int main(int argc, char* argv[]) +{ + // + // Using a local variable to hold the ShopSim object is + // safe because the stack of the global main() function + // won't be touched during a simulation. The stacks of + // the Process main() functions however are not available + // to each other or to the global main(). You can of course + // use dynamic allocation as seen in CustomerGen::main(). + // + ShopSim* sim = new ShopSim(); + + sim->enableDefaultLogging( XML, "Example_Shop_Log" ); + // + // The Simulation class provides different functions to + // compute the simulation. runUntil() starts computation + // until the given simulation time is reached. We have to + // use this method because our simulation does not terminate + // on its own. Which would be the case, if a Process calls + // exitSimulation() at ShopSim or if there would be no + // process scheduled for execution. + // + sim->runUntil(60 * 24 * 2); + + // + // The report is generated at this moment. All registered + // objects must be alive and ready to add their parts to + // the report. + // + sim->reportDefaultStatistics( XML, "Example_Shop.xml" ); + return 0; +} + diff --git a/odemx-lite/examples/Example_Statistics.cpp b/odemx-lite/examples/Example_Statistics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bcb9a1c27a3ef98daf765c69e9a1711b756f8316 --- /dev/null +++ b/odemx-lite/examples/Example_Statistics.cpp @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Example_Statistics.cpp + * @author Ronald Kluth + * @date created at 2010/04/13 + * @brief Example showing how to use the StatisticsBuffer + * @since 3.0 +*/ + +/** + * @example Example_Statistics.cpp + * The typical usage of ODEMx logging is shown. + * + * This example shows the use of the statistics channel on the producer's + * side and the use of a StatisticsBuffer on the log consumer side. + * For this purpose, the class StopWatch is again specialized in order + * to log statistical data. + */ + +#include <iostream> +#include "Example_Producer_StopWatch.h" + +using namespace odemx; + +class StatisticsStopWatch: public StopWatch { +public: + StatisticsStopWatch( base::Simulation& sim, const data::Label& label ) + : StopWatch( sim, label ) + {} + void start() { + StopWatch::start(); + // + // We count the number of uses of this object + // + statistics << count( "uses" ); + } + void stop() { + StopWatch::stop(); + // + // We compute accumulated statistics about the duration measured with + // the StopWatch. + // + statistics << update( "duration", StopWatch::getDuration() ); + } +}; + +int main() { + using data::buffer::StatisticsBuffer; + typedef std::shared_ptr< StatisticsBuffer > BufferPtr; + base::Simulation& sim = getDefaultSimulation(); + // + // Initializing the buffer with true mean we want to store update pairs. + // + BufferPtr buf = StatisticsBuffer::create( sim, "Statistics Buffer", true ); + sim.addConsumer( data::channel_id::statistics, buf ); + // + // In order to produce a good value distribution, we use the watch + // 10000 times. + // + odemx::random::Normal normal( sim, "Normal Distribution", 42, 5 ); + StatisticsStopWatch watch( sim, "Statistics Stop Watch" ); + int i = 10000; + while( i-- ) { + watch.start(); + sim.setCurrentTime( sim.getTime() + normal.sample() ); + watch.stop(); + } + // + // Now we can use the stored update pairs to produce a histogram + // for displaying the normal distribution. + // + const StatisticsBuffer::UpdateDeque& updates = buf->getUpdates( watch.getLabel(), "duration" ); + statistics::Histogram histogram( sim, "StopWatch Duration", 20, 70, 25 ); + for( StatisticsBuffer::UpdateDeque::size_type i = 0; i < updates.size(); ++i ) { + histogram.update( updates[ i ].second ); + } + + data::output::OStreamReport report( std::cout ); + report.addReportProducer( *buf ); + report.addReportProducer( histogram ); + report.generateReport(); +} diff --git a/odemx-lite/examples/Example_Wait_Timer_Port.cpp b/odemx-lite/examples/Example_Wait_Timer_Port.cpp new file mode 100644 index 0000000000000000000000000000000000000000..278459ac64e0355b08c256335454a3f65b1a8bb1 --- /dev/null +++ b/odemx-lite/examples/Example_Wait_Timer_Port.cpp @@ -0,0 +1,211 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Example_Wait_Timer_Port.cpp + + \author Ronald Kluth + + \date created at 2007/10/01 + + \brief A short usage example of Ports and Timers + + \since 2.0 +*/ + +/** + * @example Example_Wait_Timer_Port.cpp + * The typical usage of the ODEMx process wait concept is demonstrated. + * + * A receiver process has both, a timer and a port. When a timeout occurs, + * the receiver process finishes its run. A event is used to put three messages + * into the receiver's input port, and while there is data, the receiver + * reads it from the port. Eventually, it runs out of data and a timeout + */ + +#include <iostream> +#include <string> +using namespace std; + +#include <odemx/odemx.h> +using namespace odemx::base; +using namespace odemx::synchronization; + +//---------------------------------------------------------------------------Msg +// +// Since we want to use the default ports provided by odemx, we need the +// port elements to be derived from PortData. Here, we define a simple +// message type that transports a string. +// +struct Msg: public PortData +{ + Msg( const string& str ): content( str ) {} + virtual Msg* clone() { return 0; } + string content; +}; + +//----------------------------------------------------------------------Receiver +// +// The receiver of messages is a process that allows us to demonstrate the use +// of the concept wait-for-alert. +// +class Receiver: public Process +{ +public: + Receiver() + : Process( odemx::getDefaultSimulation(), "The Receiver" ) + , timer_( new Timer( odemx::getDefaultSimulation(), "Receiver Message Timer" ) ) + , port_( PortHead::create( odemx::getDefaultSimulation(), "Receiver Input Port" ) ) + {} + // + // The life cycle of this process uses wait() to stop its run until a + // Memory object becomes available, i.e. the process gets alerted by it. + // After checking who the alerter is, appropriate action is taken by either + // logging the message and calling wait again, or by finishing its run if + // a timeout occurs. + // + virtual int main() + { + // + // Protect the receiver from deadlock by setting a timer. + // + SimTime timeLimit = 10; + timer_->setIn( timeLimit ); + bool timeOut = false; + + while( ! timeOut ) + { + info << log( "waiting for next message with timeout at" ) + .detail( "time", timer_->getExecutionTime() ); + // + // Wait for message arrival at the port, or a timeout. + // + IMemory* who = wait( timer_.get(), port_.get() ); + // + // When arriving at this point, the process was either alerted + // by a Memory object or interrupted by some other object. + // + if( who == timer_.get() ) + { + // + // Timeout, stop message reception loop. + // + info << log( "alerted by timer" ).detail( "timeout at", getTime() ); + timeOut = true; + } + else if( who == port_.get() ) + { + info << log( "alerted by port" ); + // + // Restart the timer for the next waiting period. + // + timer_->reset( timeLimit ); + // + // PortHead::get() return an auto_ptr wrapping the actual + // pointer to the message. The returned data can be 0, if an + // error occurred. + // + std::unique_ptr< PortData* > data = port_->get(); + if( data.get() != 0 ) + { + // + // We need to manage memory allocated by MessageArrival event + // + std::unique_ptr< Msg > msg( static_cast< Msg* >( *data ) ); + info << log( "received message" ).detail( "content", msg->content ); + } + else + { + error << log( "PortHead::get() returned 0" ); + } + } + } + info << log( "terminated at" ).detail( "time", getTime() ); + return 0; + } + + PortHead::TailPtr getInputPort() { return port_->getTail(); } + +private: + std::unique_ptr< Timer > timer_; + PortHead::Ptr port_; +}; + +//----------------------------------------------------------------MessageArrival +// +// The arrival of messages is modeled by a simple event class that puts +// messages into a receiver's input port. +// +class MessageArrival: public Event +{ +public: + MessageArrival( Receiver& receiver ) + : Event( odemx::getDefaultSimulation(), "Message Arrival" ) + , receiver_( &receiver ) + {} + // + // The event action simply models the arrival of three messages at a port + // + virtual void eventAction() + { + info << log( "triggered for" ).detail( "receiver", receiver_->getLabel() ); + receiver_->getInputPort()->put( new Msg( "message 1" ) ); + receiver_->getInputPort()->put( new Msg( "message 2" ) ); + receiver_->getInputPort()->put( new Msg( "message 3" ) ); + } + +private: + Receiver* receiver_; +}; + +//--------------------------------------------------------------------------main + +int main( int argc, char* argv[] ) +{ + using namespace odemx::data::output; + + SimTime arrivalTime = 8; + Simulation& sim = odemx::getDefaultSimulation(); + + Receiver receiver; + MessageArrival arrival( receiver ); + arrival.scheduleAt( arrivalTime ); + receiver.activate(); + + sim.addConsumer( odemx::data::channel_id::info, OStreamWriter::create( std::cout ) ); + sim.run(); + return 0; +} + +//----------------------------------------------------------------program output +/* +ODEMx Log +========= +0 info: The Receiver(Receiver) waiting for next message with timeout at [Details: # time=10] +8 info: Message Arrival(MessageArrival) triggered for [Details: # receiver=The Receiver] +8 info: The Receiver(Receiver) alerted by port +8 info: The Receiver(Receiver) received message [Details: # content=message 1] +8 info: The Receiver(Receiver) waiting for next message with timeout at [Details: # time=18] +8 info: The Receiver(Receiver) alerted by port +8 info: The Receiver(Receiver) received message [Details: # content=message 2] +8 info: The Receiver(Receiver) waiting for next message with timeout at [Details: # time=18] +8 info: The Receiver(Receiver) alerted by port +8 info: The Receiver(Receiver) received message [Details: # content=message 3] +8 info: The Receiver(Receiver) waiting for next message with timeout at [Details: # time=18] +18 info: The Receiver(Receiver) alerted by timer [Details: # timeout at=18] +18 info: The Receiver(Receiver) terminated at [Details: # time=18] +*/ diff --git a/odemx-lite/external/CppLog/COPYING b/odemx-lite/external/CppLog/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..d93b3566ca8f266088efadf48019e0c9163fb7aa --- /dev/null +++ b/odemx-lite/external/CppLog/COPYING @@ -0,0 +1,4 @@ +Copyright (c) 2009-2010 Ronald Kluth + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/odemx-lite/external/CppLog/CppLog.kdev4 b/odemx-lite/external/CppLog/CppLog.kdev4 new file mode 100644 index 0000000000000000000000000000000000000000..2c317a6a60741d065c153e1b1fda372947069a82 --- /dev/null +++ b/odemx-lite/external/CppLog/CppLog.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevGenericManager +Name=CppLog diff --git a/odemx-lite/external/CppLog/INSTALL b/odemx-lite/external/CppLog/INSTALL new file mode 100644 index 0000000000000000000000000000000000000000..87c92adadeb3383cef6ef86b51648313e521cf01 --- /dev/null +++ b/odemx-lite/external/CppLog/INSTALL @@ -0,0 +1,3 @@ +See Doxygen documentation for information on: + - Using CppLog + - How to build the tests and examples diff --git a/odemx-lite/external/CppLog/LICENSE_1_0.txt b/odemx-lite/external/CppLog/LICENSE_1_0.txt new file mode 100644 index 0000000000000000000000000000000000000000..36b7cd93cdfbac762f5be4c6ce276df2ea6305c2 --- /dev/null +++ b/odemx-lite/external/CppLog/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/odemx-lite/external/CppLog/README b/odemx-lite/external/CppLog/README new file mode 100644 index 0000000000000000000000000000000000000000..9e9318a97e3532106d95281c63337efd6c45d3e2 --- /dev/null +++ b/odemx-lite/external/CppLog/README @@ -0,0 +1,4 @@ +CppLog version 0.1 +Released Wednesday, 05 May 2010. + +See Doxygen documentation for API documentation and examples. diff --git a/odemx-lite/external/CppLog/doc/Doxyfile b/odemx-lite/external/CppLog/doc/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..df862b8e5697b1709b76bd2b1017ba7f7f6958b7 --- /dev/null +++ b/odemx-lite/external/CppLog/doc/Doxyfile @@ -0,0 +1,1501 @@ +# Doxyfile 1.5.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = CppLog + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" "The $name widget" "The $name file" is provides specifies contains represents a an the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py *.f90 *.f *.vhd *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = ../src/test ../include/CppLog/detail/string_literal.hpp ../include/CppLog/detail/Bindings.h ../include/CppLog/detail/EnableIf.h + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = ../src/samples/src/ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = ALL + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = YES + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = DOXYGEN_SKIP + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/odemx-lite/external/CppLog/doc/MainPage.dox b/odemx-lite/external/CppLog/doc/MainPage.dox new file mode 100644 index 0000000000000000000000000000000000000000..e50f6c876aa26c10986b6658c9453a83ba08dd4d --- /dev/null +++ b/odemx-lite/external/CppLog/doc/MainPage.dox @@ -0,0 +1,50 @@ +/** + @mainpage + + @section Introduction + Welcome to CppLog, a slim, template-based C++ logging library. + + \n + With regard to Software, logging refers to the collection and + visualization of runtime state information of a program. The most + simple variant of logging is writing console output, which is + usually problematic because it cannot easily be disabled (aside + from removing the statements in the code). In addition, console + output quickly becomes hard to read and follow when the logged data + reaches a sizeable amount. The next logical step is to use specialized + components that allow formatting and archiving of log records in + files or databases. That is the area CppLog is aimed at. + The library comes in header-only form and provides simple yet powerful + core components to facilitate application logging in C++ projects. + + The philosophy of the library is to make as few assumptions as + possible about what kinds of data are to be logged and how that is + to be achieved. Therefore, the library does not limit users to + one specific record type but rather provides templates that allow + the specification of any user-defined type. Naturally, as with most + template code, this puts some limitations on what the library can offer + in terms of ease-of-use. + + In order to address that fact, a default record type has been included + so that several default output components could be defined as well. + These provide stream-writing support for plain text and XML, and + additionally an XML file writer. Database support is also included + but introduces a dependency on the Poco C++ libraries + (http://pocoproject.org). + + \section installation Installation + There is no installation procedure required for using the core + components of CppLog. Simply copy the files into a directory that + is present in the compiler's include path. + + However, for database connectivity, CppLog is currently dependent + on the use of the Poco C++ libraries. These provide an interface for + communicating with SQLite and ODBC databases. Besides that, simple + Makefiles are included for compiling the examples and the test suite. + + \section copyright Copyright and License + Copyright (c) 2009-2010 Ronald Kluth. + The library is istributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +*/ diff --git a/odemx-lite/external/CppLog/include/CppLog.h b/odemx-lite/external/CppLog/include/CppLog.h new file mode 100644 index 0000000000000000000000000000000000000000..833aac8358b2f244ca5ca7204c27f5cdd2f51c53 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog.h @@ -0,0 +1,46 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file CppLog.h + * @author Ronald Kluth + * @date 2009/05/17 + * @brief Forwarding header for all CppLog classes and macros + * @since 0.1 + */ + +#ifndef CPPLOG_INCLUDED +#define CPPLOG_INCLUDED + +// include library setup, enables/disables database connectivity +#include "setup.h" + +// include core components +#include "CppLog/Channel.h" +#include "CppLog/ChannelId.h" +#include "CppLog/ChannelManager.h" +#include "CppLog/Consumer.h" +#include "CppLog/DeclareChannel.h" +#include "CppLog/DeclareInfoType.h" +#include "CppLog/DeclareInfoTypeList.h" +#include "CppLog/DeclareSqlColumnTypes.h" +#include "CppLog/Enable.h" +#include "CppLog/Filter.h" +#include "CppLog/NamedElement.h" +#include "CppLog/NameScope.h" +#include "CppLog/Producer.h" +#include "CppLog/Record.h" +#include "CppLog/StringLiteral.h" + +// include output components +#include "CppLog/output/OStreamWriter.h" +#include "CppLog/output/XmlFileWriter.h" +#include "CppLog/output/XmlStreamWriter.h" +#include "CppLog/output/XmlWriter.h" +#include "CppLog/output/DatabaseAccessor.h" + +#endif /* CPPLOG_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/Channel.h b/odemx-lite/external/CppLog/include/CppLog/Channel.h new file mode 100644 index 0000000000000000000000000000000000000000..5a296141cbdd9ffb3f3868a0a8e199fe6c537060 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/Channel.h @@ -0,0 +1,286 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Channel.h + * @author Ronald Kluth + * @date 2009/02/08 + * @brief Declaration and implementation of class template Channel and operator<< + * @since 0.1 + */ + +#ifndef LOG_CHANNEL_INCLUDED +#define LOG_CHANNEL_INCLUDED + +#include "ChannelId.h" +#include "Consumer.h" +#include "Filter.h" + +#include <cassert> +#include <set> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + + +namespace Log { + +/** + * @brief Class template for log channels that forward records to registered consumers + * @tparam RecordT Type of the log records to be used, the default is @c Record + * + * A channel provides the means to transport log records from any source to + * any number of consumers. Channels are used in a stream-like manner via an + * overloaded @c operator<<. Besides the registration of consumers, channels + * also allow for a filter to be set. + * + * Multiple channel objects of the same type can be created and controlled + * by a manager object to ensure they have the same lifetime, or to access + * several channels simultaneously when adding or removing consumers and + * record filters. + * + * Usage: + * @code + * Channel< std::string > channel; + * channel.addConsumer( con1 ); + * channel.addConsumer( con2 ); + * channel << std::string( "example message" ); + * @endcode + * + * In the above usage example, the message is forwarded to both registered + * consumers @c con1 and @c con2. + * + * @note This class is not intended to be inherited. + * @see ChannelId, Consumer, Filter, ChannelManager, Log::operator<< + */ +template < typename RecordT = Record > +class Channel +{ +public: + /// Type of the records to be logged + typedef RecordT RecordType; + /// Pointer type to manage registered log record consumers + typedef std::shared_ptr< Consumer< RecordType > > ConsumerPtr; + /// Set type to store pointers to record consumers + typedef std::set< ConsumerPtr > ConsumerSet; + /// Pointer type to manage RecordFilter objects + typedef std::shared_ptr< Filter< RecordType > > FilterPtr; + + /** + * @brief Construction with ID, or default construction with -1 + * + * Channels may specify an ID in order to allow consumers to identity + * which channel forwarded a record. + */ + explicit Channel( ChannelId const channelId = -1 ) + : id_( channelId ) + , filter_() + , consumers_() + { + } + + // Compiler-generated dtor o.k. + + /** + * @brief Get the channel's ID value set during contruction + * + * Channel IDs can be used by consumers to identify the channel that + * forwarded log records. The default setting is -1, meaning the channel + * was not given an ID. + * + * @return ID of the channel object, or -1 if not set + */ + ChannelId const getId() const + { + return id_; + } + + /** + * @brief Get access to the set of registered log record consumers + * + * This method is used by @c operator<< to iterate over all registered + * consumers in order to forward the log record via the @c Consumer + * interface. + * + * @return Reference to the set of consumers + * @see Consumer + */ + ConsumerSet const& getConsumers() const + { + return consumers_; + } + + /** + * @brief Check whether the filter is set + * @return @c true if the @c shared_ptr holding the filter is not empty + */ + bool hasFilter() const + { + return !!filter_; + } + + /** + * @brief Get a pointer to the channel's record filter + * @return A copy of the @c shared_ptr holding the filter + */ + FilterPtr getFilter() const + { + return filter_; + } + + /** + * @brief Set a (new) record filter for the channel + * @param filter @c shared_ptr to a filter, must not be empty + * + * This method resets the filter pointer to the given parameter. + * A channel may only hold one filter. Thus, calling this method replaces + * the previous filter, if one was set. + */ + void setFilter( FilterPtr filter ) + { + assert( filter ); + filter_ = filter; + } + + /** + * @brief Reset the record filter + * + * This method resets the @c shared_ptr managing the filter. If the channel + * holds the last reference to the filter, it will be automatically deleted. + */ + void resetFilter() + { + filter_.reset(); + } + + /** + * @brief Add another consumer to the channel + * @param consumer @c shared_ptr to a consumer, must not be empty + * + * This method adds a new consumer to the channel's set. Consumer objects + * are managed by @c shared_ptr so their existence is ensured until the last + * channel holding a reference to them is destroyed. + * + * @retval true if the consumer was inserted successfully + * @retval false if the consumer was already registered + */ + bool addConsumer( ConsumerPtr consumer ) + { + assert( consumer ); + return ( consumers_.insert( consumer ).second ); + } + + /** + * @brief Remove a consumer from the channel's set + * @param consumer @c shared_ptr to a consumer, must not be empty + * + * This method removes the given consumer from the channel's set, + * thereby decreasing its @c shared_ptr reference count by one. If the + * channel held the last reference to the consumer, the object is + * automatically deleted. + * + * @retval true if the consumer was found and erased + * @retval false if the consumer was not found in the set + */ + bool removeConsumer( ConsumerPtr consumer ) + { + assert( consumer ); + return ( consumers_.erase( consumer ) > 0 ); + } + + /** + * @brief Remove all consumers from the channel + * + * This method clears the set of registered consumers, which effectively + * disables a channel because no records can be forwarded via @c operator<< + * anymore. + */ + void removeConsumers() + { + consumers_.clear(); + } + +private: + /// Constant member to identify this channel object + ChannelId const id_; + /// Pointer to a record filter object associated with this channel + FilterPtr filter_; + /// Container of registered consumers which receive all records forwarded by this channel + ConsumerSet consumers_; + + /// Non-copyable + Channel( Channel const& ); + /// Non-assignable + Channel& operator=( Channel const& ); +}; + +/** + * @brief Inserter overload for stream-like use of log channels + * @tparam RecordT Type of the records to be forwarded by the channel + * + * This overload of the insert operator provides the means to forward + * any kind of log records via any matching channel. The channel is checked + * for a filter, and if one is set, the given record must pass it in order to + * be forwarded to all the channel's consumers. + * + * @see Channel, Consumer + */ +template < typename RecordT > +inline +Channel< RecordT > const& +operator<<( Channel< RecordT > const& channel, RecordT const& record ) +{ + // check if the channel is filtered and if the record may pass + if( ! channel.hasFilter() || channel.getFilter()->pass( record ) ) + { + // pass the record on to the channel's consumers + // by calling consume on each one with channel ID and record + for( typename Channel< RecordT >::ConsumerSet::const_iterator + iter = channel.getConsumers().begin(); + iter != channel.getConsumers().end(); + ++iter ) + { + ( *iter )->consume( channel.getId(), record ); + } + } + return channel; +} + +/** + * @brief Inserter overload for @c shared_ptr to channel objects + * @tparam RecordT Type of the records to be forwarded by the channel + * + * This overload of the insert operator logs data only if the @c shared_ptr + * is set. This makes it possible for record producers to enable/disable + * logging dynamically by simply setting or resetting a @c shared_ptr to + * the channel. Using a @c shared_ptr to manage channel access can also be + * useful if log records are expensive to create. The pointer can be checked + * by a condition so that the insertion statement is only executed when the + * pointer is actually set. + * + * @note This operator uses the other overload for references to channels. + * @see Channel, Consumer, Log::operator<< + */ +template < typename RecordT > +inline +std::shared_ptr< Channel< RecordT > > const +operator<<( std::shared_ptr< Channel< RecordT > > const channel, RecordT const& record ) +{ + // log only if the channel is set, allows disabling logging per producer + // because it can just reset its shared_ptr if logging is not needed + if( channel ) + { + *channel << record; + } + return channel; +} + +} // namespace Log + +#endif /* LOG_CHANNEL_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/ChannelId.h b/odemx-lite/external/CppLog/include/CppLog/ChannelId.h new file mode 100644 index 0000000000000000000000000000000000000000..2343404a4b870338dd7e8ead1992fb86d5a8fbcd --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/ChannelId.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file ChannelId.h + * @author Ronald Kluth + * @date created at 2009/03/11 + * @brief Declaration of type ChannelId + * @since 0.1 + */ + +#ifndef LOG_CHANNELID_INCLUDED +#define LOG_CHANNELID_INCLUDED + +namespace Log { + +/** + * @typedef ChannelId + * @brief An alias to make the use of channel IDs more obvious in the code. + * + * Every @c Channel object can be constructed with an ID. The default is -1, + * meaning that it is not set. Channel IDs can be used by consumers to identify + * the channel that forwarded a log record via call to @c consume. The consumer + * interface ensures that the @c ChannelId of the caller is given. + * + * @see Channel, Consumer + */ +typedef int ChannelId; + +} // namespace Log + +#endif /* LOG_CHANNELID_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/ChannelManager.h b/odemx-lite/external/CppLog/include/CppLog/ChannelManager.h new file mode 100644 index 0000000000000000000000000000000000000000..65ef0f57fb00360bd56ca4c9d6018470a384b2be --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/ChannelManager.h @@ -0,0 +1,325 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file ChannelManager.h + * @author Ronald Kluth + * @date created at 2009/06/05 + * @brief Declaration and implementation of class template ChannelManager + * @since 0.1 + */ + +#ifndef LOG_CHANNELMANAGER_INCLUDED +#define LOG_CHANNELMANAGER_INCLUDED + +#include "ChannelId.h" +#include "NameScope.h" + +#include <cassert> +#include <map> + +#ifdef _MSC_VER +#include <memory> +#include <functional> // bind +#else +#include <memory> +#include <functional> // bind +#endif + + +namespace Log { + +// forward declarations +template < typename > class Channel; +template < typename > class Consumer; +template < typename > class Filter; +class Record; + +/** + * @brief Manager template type that creates and manages log channels for producers + * @tparam RecordT Type of the log records the channels can use + * + * A channel manager serves two purposes. Firstly, it can be used to + * create multiple channels of the same type (i.e. channels using the + * same record type) and simplify their consumer and filter management. + * Secondly, it may serve as name scope and channel provider for producer + * classes. + * + * Usage: + * @code + * ChannelManager< std::string > mgr; + * shared_ptr< Channel< std::string > chan1 = mgr.getChannel( 1 ); + * shared_ptr< Channel< std::string > chan2 = mgr.getChannel( 2 ); + * mgr.addConsumer( con ); + * chan1 << std::string( "Channel 1 message" ); + * chan2 << std::string( "Channel 2 message" ); + * mgr.removeConsumer( 2, con ); + * @endcode + * + * The above snippet shows the creation of a manager and the retrieval of two + * pointers to log channels via @c getChannel. Since the manager does not yet + * own channels with IDs 1 and 2, it creates them at the first request. Now + * that the channels exist, we can register a consumer with the manager, which + * will pass them along to all of its currently owned channels. Hence, both + * subsequently sent log records will be passed on to the consumer @c con. + * The manager also allows to add or remove consumers for specific channels, + * as is shown in the last line. + * + * @note Pairing incompatible producer and channel manager types + * will most likely result in compile errors. + * @see Producer, Channel, ChannelId, Consumer, Filter + */ +template < typename RecordT = Record > +class ChannelManager +: public NameScope +{ +public: + /// The record type used by the log channels + typedef RecordT RecordType; + /// The channel type of the managed channels + typedef Channel< RecordType > ChannelType; + /// Pointer type to manage channels + typedef std::shared_ptr< ChannelType > ChannelPtr; + /// Pointer type to manage log consumers + typedef std::shared_ptr< Consumer< RecordType > > ConsumerPtr; + /// Pointer type to manage record filters + typedef std::shared_ptr< Filter< RecordType > > FilterPtr; + /// Map type to associate channel IDs with channel pointers + typedef std::map< ChannelId, ChannelPtr > ChannelMap; + + /** + * @brief Default construction + * + * This constructor uses the default name and default space character + * provided by class @c NameScope. + */ + ChannelManager() + : NameScope() + , channels_() + { + } + + /** + * @brief Construction with user-defined default name and space + * + * This constructor initializes the @c NameScope base class with a + * different default name and space character to use with named elements + * like producers. + */ + ChannelManager( std::string const& defLabel, char const defSpace ) + : NameScope( defLabel, defSpace ) + , channels_() + { + } + + /// Destruction + virtual ~ChannelManager() + { + } + + /** + * @brief Get a pointer to a managed log channel by providing its ID + * @param id The ID of the requested channel + * + * The manager first tries to find the requested channel in its map. + * If the channel does not exist yet, a new @c Channel object with the + * requested ID will be created and stored in the manager's map so that + * subsequent calls always return the same channel pointer. + */ + ChannelPtr getChannel( ChannelId const id ) + { + // get the entry or create a new one + typename ChannelMap::iterator found = channels_.find( id ); + + // if the channel is set return it + if( found != channels_.end() ) + { + return found->second; + } + + // create new channel object and make sure it's in the map + std::pair< typename ChannelMap::iterator, bool > result = + channels_.insert( typename ChannelMap::value_type( + id, ChannelPtr( new ChannelType( id ) ) ) ); + assert( result.second ); + + // return the new pointer + return result.first->second; + } + + /** + * @brief Add a log consumer to a managed log channel + * @param id ID of the channel where the consumer shall be registered + * @param consumer Pointer to the new consumer, must be valid + * + * The manager will try to find the channel and register the new + * consumer. + * + * @return @c true if the channel was found and the consumer registered + */ + bool addConsumer( ChannelId const id, ConsumerPtr consumer ) + { + typename ChannelMap::iterator found = channels_.find( id ); + if( found != channels_.end() ) + { + return found->second->addConsumer( consumer ); + } + return false; + } + + /** + * @brief Add a log consumer to all managed channels + * @param consumer Pointer to the new consumer, must be valid + * + * The manager will iterate over all channels currently stored in its map + * and register the consumer with them. + */ + void addConsumer( ConsumerPtr consumer ) + { + using namespace std::placeholders; + iterateChannels( + std::bind( &ChannelType::addConsumer, _1, consumer ) ); + } + + /** + * @brief Remove a log consumer from a managed channel + * @param id ID of the channel from which to remove the consumer + * @param consumer Pointer to the consumer + * + * The manager will try to find the channel and remove the existing + * consumer. + * + * @return @c true if the channel was found and the consumer removed + */ + bool removeConsumer( ChannelId const id, ConsumerPtr consumer ) + { + typename ChannelMap::iterator found = channels_.find( id ); + if( found != channels_.end() ) + { + return found->second->removeConsumer( consumer ); + } + return false; + } + + /** + * @brief Remove a log consumer from all managed channels + * @param consumer Pointer to the consumer + * + * The manager will iterate over all channels currently stored in its map + * and remove the given consumer. + */ + void removeConsumer( ConsumerPtr consumer ) + { + using namespace std::placeholders; + iterateChannels( + std::bind( &ChannelType::removeConsumer, _1, consumer ) ); + } + + /** + * @brief Set a record filter for a managed channel + * @param id ID of the channel on which to set the filter + * @param filter Pointer to the new filter + * + * The manager will try to find the channel and set the filter. + * + * @note This will replace the current filter of the channel. + * @return @c true if the channel was found and the filter set + */ + bool setFilter( ChannelId const id, FilterPtr filter ) + { + typename ChannelMap::iterator found = channels_.find( id ); + if( found != channels_.end() ) + { + found->second->setFilter( filter ); + return true; + } + return false; + } + + /** + * @brief Set a record filter for all managed channels + * @param filter Pointer to the new filter + * + * The manager will iterate over all channels currently stored in its map + * and set the given filter. + * + * @note This will replace any filters set on the channels + */ + void setFilter( FilterPtr filter ) + { + assert( filter ); + using namespace std::placeholders; + iterateChannels( + std::bind( &ChannelType::setFilter, _1, filter ) ); + } + + /** + * @brief Reset the record filter of a managed channel + * @param id ID of the channel on which to reset the filter + * + * The manager will try to find the channel and reset the filter. + * + * @return @c true if the channel was found and the filter reset + */ + bool resetFilter( ChannelId const id ) + { + typename ChannelMap::iterator found = channels_.find( id ); + if( found != channels_.end() ) + { + found->second->resetFilter(); + return true; + } + return false; + } + + /** + * @brief Reset the record filter for all managed channels + * + * The manager will iterate over all channels currently stored in its map + * and reset their filters. + */ + void resetFilter() + { + using namespace std::placeholders; + iterateChannels( + std::bind( &ChannelType::resetFilter, _1 ) ); + } + +private: + /// Storage for channel pointers, indexed by the channel IDs + ChannelMap channels_; + +private: + /// Non-copyable + ChannelManager( ChannelManager const& ); + /// Non-assignable + ChannelManager& operator=( ChannelManager const& ); + + /** + * @brief Execute a callable entity on all managed channels + * @param func The callable entity to execute for all channels + * + * This method template takes any callable entity as parameter, iterates + * over the map of channels and calls @c func for each channel. Typically, + * @c func is a functor created by @c bind that calls a member function of + * the channel. + */ + template < typename FuncT > + void iterateChannels( FuncT const& func ) + { + typename ChannelMap::iterator iter; + for( iter = channels_.begin(); iter != channels_.end(); ++iter ) + { + assert( iter->second ); + func( iter->second ); + } + } +}; + +} // namespace Log + +#endif /* LOG_CHANNELMANAGER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/Consumer.h b/odemx-lite/external/CppLog/include/CppLog/Consumer.h new file mode 100644 index 0000000000000000000000000000000000000000..b1f841d6916d0c701a4075443c94b2761056a6f8 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/Consumer.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Consumer.h + * @author Ronald Kluth + * @date created at 2009/02/08 + * @brief Declaration and Implementation of interface Consumer + * @since 0.1 + */ + +#ifndef LOG_CONSUMER_INCLUDED +#define LOG_CONSUMER_INCLUDED + +#include "ChannelId.h" + +namespace Log { + +// forward declaration +class Record; + +/** + * @interface Consumer + * @brief Interface for classes that can consume records from log channels. + * @tparam RecordT Type of the records received from channels, the default + * is @c Record + * + * All log consumer classes must be derived from this class in order to be + * compatible with log channels (which store pointers to registered consumers). + * In addition, the channel and consumers must be templated on the same record + * type. The derived classes must override the method @c consume that defines + * how to handle records. + * + * Usage: + * @code + * class ConsoleWriter: public Log::Consumer< std::string > { + * public: + * virtual void consume( Log::ChannelId const channelId, std::string const& record ) { + * std::cout << record << std::flush; + * } + * }; + * Log::Channel< std::string > channel; + * channel.addConsumer( std::shared_ptr< ConsoleWriter >( new ConsoleWriter() ) ); + * @endcode + * + * @see Channel, Log::operator<< + * @ref Example_Channel_Consumer.cpp + */ +template < typename RecordT = Record > +class Consumer +{ +public: + /// Type of the log records to consume + typedef RecordT RecordType; + + // Compiler-generated ctor, assignment o.k. + +protected: + /// Destruction + virtual ~Consumer() {} + +public: + /** + * @brief Pure virtual method for consuming records + * @param id A numerical value to identify which channel forwarded the record + * @param record The currently forwarded record + * + * Whenever a record is sent through a channel, the channel forwards + * it to all registered consumers by calling this method on them. + * Usually, consumers then transform this record into readable information + * and/or store it for later access. + * + * @note The record that is passed as reference to const most likely is a + * a temporary object. In order to store its data for later use, the + * consumer must copy it, for example by storing it in an STL container. + * + * @note Special care must be taken to ensure that stored records do not + * reference deleted objects, and end up accessing dangling pointers. + */ + virtual void consume( ChannelId const id, RecordType const& record ) = 0; +}; + +} // namespace Log + +#endif /* LOG_CONSUMER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/DeclareChannel.h b/odemx-lite/external/CppLog/include/CppLog/DeclareChannel.h new file mode 100644 index 0000000000000000000000000000000000000000..94e948897928263e3079252ab762fb258cfbeade --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/DeclareChannel.h @@ -0,0 +1,101 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file DeclareChannel.h + * @author Ronald Kluth + * @date created at 2009/06/05 + * @brief Declaration and implementation of macro CPPLOG_DECLARE_CHANNEL + * @since 0.1 + */ + +#ifndef LOG_DECLARECHANNEL_INCLUDED +#define LOG_DECLARECHANNEL_INCLUDED + +#include "Channel.h" +#include "ChannelManager.h" +#include "detail/ChannelField.h" + +/** + * @def CPPLOG_DECLARE_CHANNEL_WITH_ID( PP_NameSpace, PP_IdName, PP_RecordType, PP_Id ) + * @brief Declaration of a log channel, corresponding ID, name, and producer member + * @param PP_NameSpace The namespace the ID should reside in + * @param PP_IdName The name of the channel ID to be created, also the member name + * @param PP_RecordType The type of records the channel transports + * @param PP_Id The value of the ID, must be unique for each macro use + * + * This macro has the same effect as @c CPPLOG_DECLARE_CHANNEL, but it allows + * the manual specification of the channel ID value. It is mainly provided for + * legacy compilers that do not support the use of the @c __COUNTER__ macro and + * thus cannot create ID values automatically. + * + * @note Since this macro creates template specializations, all uses must + * have unique ID values in order to create different log channels. + * @see CPPLOG_DECLARE_CHANNEL, Producer, ChannelManager + */ +#define CPPLOG_DECLARE_CHANNEL_WITH_ID( PP_NameSpace, PP_IdName, PP_RecordType, PP_Id ) \ + namespace PP_NameSpace { enum { PP_IdName = PP_Id }; } \ + namespace Log { \ + namespace Detail { \ + template <> \ + struct ChannelField< ::PP_NameSpace::PP_IdName > \ + { \ + ChannelField() {} \ + ChannelField( ChannelManager< PP_RecordType >& manager ) \ + { \ + this->PP_IdName = manager.getChannel( ::PP_NameSpace::PP_IdName ); \ + } \ + protected: \ + std::shared_ptr< Log::Channel< PP_RecordType > > PP_IdName; \ + }; \ + } } // namespace Log::Detail + +/** + * @def CPPLOG_DECLARE_CHANNEL( PP_NameSpace, PP_IdName, PP_RecordType ) + * @brief Declares a log channel with corresponding ID and record type + * @param PP_NameSpace The namespace the ID should reside in + * @param PP_IdName The name of the channel ID to be created, also the member name + * @param PP_RecordType The type of records the channel transports + * + * This macro is used to declare log channels which are intended for + * use with producers and channel managers. In this pattern, the manager will + * create and manage channel objects with the given IDs, and the producer can + * automatically use these channels as @c shared_ptr members of the same name. + * + * Usage: + * @code + * CPPLOG_DECLARE_CHANNEL( channel_id, info, std::string ) + * @endcode + * + * The above declaration creates an anonymous enum in namespace + * @c channel_id that contains @c info. Thus, the ID can be referred to as + * @c channel_id::info. This identifier can then be used in conjunction + * with the class templates @c Producer and @c Enable to activate log + * channel access for a producer class by instantiating the template. + * Log data producers can then be derived from that type and use the + * log channel @c info (which is automatically initialized by calling + * @c getChannel on the manager) as follows: + * + * @code + * typedef Log::Producer< Log::Enable< channel_id::info > > InfoProducer; + * + * class DataProducer + * { + * public: + * DataProducer( Log::ChannnelManager< std::string >& mgr, const std::string& name ) + * : InfoProducer( mgr, name ) + * { + * info << std::string( "example message" ); + * } + * }; + * @endcode + * @see Producer, ChannelManager + */ +#define CPPLOG_DECLARE_CHANNEL( PP_NameSpace, PP_IdName, PP_RecordType ) \ + CPPLOG_DECLARE_CHANNEL_WITH_ID( PP_NameSpace, PP_IdName, PP_RecordType, __COUNTER__ ); + +#endif /* LOG_DECLAREMANAGEDCHANNEL_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/DeclareInfoType.h b/odemx-lite/external/CppLog/include/CppLog/DeclareInfoType.h new file mode 100644 index 0000000000000000000000000000000000000000..e3b76f3a304b87ccc40b4784fc95e5a320406e41 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/DeclareInfoType.h @@ -0,0 +1,66 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file DeclareInfoType.h + * @author Ronald Kluth + * @date created at 2009/06/05 + * @brief Declaration and implementation of macro CPPLOG_DECLARE_INFO_TYPE + * @since 0.1 + */ + +#ifndef LOG_DECLAREINFOTYPE_INCLUDED +#define LOG_DECLAREINFOTYPE_INCLUDED + +#include "StringLiteral.h" +#include "detail/InfoType.h" + +/** + * @def CPPLOG_DECLARE_INFO_TYPE( PP_InfoTypeName, PP_StringName, PP_ValueType ) + * @brief Macro to ease the creation of arbitrary record info types + * @param InfoTypeName The actual type name to be used + * @param StringName String representation for this type + * @param ValueType Type of the values the info type objects hold + * + * This macro is used to create record info types. In order for records to + * carry arbitrary values, these must be wrapped by @c InfoType classes. + * When expanded by the C++ preprocessor, this macro creates a new @c struct + * that is used as a tag to distinguish specializations of the class template + * InfoType holding the same value type. + * Additionally, it provides a static method @c getName that returns the given + * string representation (the second macro parameter). This string can be used + * during the automatic extraction of log record info data, e.g. to associate + * a piece of data with a table column in a database. The third macro parameter + * defines the type of the values this info type can hold. The value to be + * carried must be passed with the constructor and cannot be changed afterwards. + * Info types can transport copies as well as pointers or references to data. + * + * Example: + * @code + * CPPLOG_DECLARE_INFO_TYPE( FuncInfo, "Function", std::string ); + * Channel< Record > channel; + * void foo() + * { + * channel << Record( "function called" ) + FuncInfo( "foo()" ); + * } + * @endcode + */ +#define CPPLOG_DECLARE_INFO_TYPE( PP_InfoTypeName, PP_StringName, PP_ValueType ) \ + \ + struct PP_InfoTypeName##NameHolder \ + { \ + static const Log::StringLiteral& getName() \ + { \ + static Log::StringLiteral name( PP_StringName ); \ + return name; \ + } \ + }; \ + \ + typedef Log::Detail::InfoType< PP_InfoTypeName##NameHolder, PP_ValueType > PP_InfoTypeName; + + +#endif /* LOG_DECLAREINFOTYPE_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/DeclareInfoTypeList.h b/odemx-lite/external/CppLog/include/CppLog/DeclareInfoTypeList.h new file mode 100644 index 0000000000000000000000000000000000000000..3f91bcaa877bb0af1c9ed0677e0703042cf77c4f --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/DeclareInfoTypeList.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file DeclareInfoTypeList.h + * @author Ronald Kluth + * @date created at 2009/06/09 + * @brief Declaration and implementation of macro CPPLOG_DECLARE_INFO_TYPE_LIST + * @since 0.1 + */ + +#ifndef LOG_DECLAREINFOTYPELIST_INCLUDED +#define LOG_DECLAREINFOTYPELIST_INCLUDED + +#ifdef _MSC_VER +#include <tuple> +#else +#include <tuple> +#endif + +/** + * @def CPPLOG_DECLARE_INFO_TYPE_LIST( PP_InfoListName, ... ) + * @brief This macro allows the creation of info type lists + * @param PP_InfoListName Type name of the list of info types + * + * Lists of info types are used in the automatic extraction of the data + * transported by Record objects. The first macro parameter specifies the + * type name of the list type, followed by a variable number of parameters, + * all of which must be info types declared with @c CPPLOG_DECLARE_INFO_TYPE. + * The implementation of these type lists is provided by the standard library + * class template @c tuple (added in TR1). The two helper templates + * @c tuple_size and @c tuple_element are used to iterate over the list at + * compile time. + * + * @see CPPLOG_DECLARE_INFO_TYPE + */ +#define CPPLOG_DECLARE_INFO_TYPE_LIST( PP_InfoListName, ... ) \ + typedef std::tuple < __VA_ARGS__ > PP_InfoListName; + +#endif /* LOG_DECLAREINFOTYPELIST_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/DeclareSqlColumnTypes.h b/odemx-lite/external/CppLog/include/CppLog/DeclareSqlColumnTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..0714985d4c18c2ffe3c25f432fd05e6a154ae458 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/DeclareSqlColumnTypes.h @@ -0,0 +1,47 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file DeclareSqlColumnTypes.h + * @author Ronald Kluth + * @date created at 2009/06/19 + * @brief Declaration and implementation of macro CPPLOG_DECLARE_SQL_COLUMN_TYPES + * @since 0.1 + */ + +#ifndef LOG_DECLARESQLCOLUMNTYPES_INCLUDED +#define LOG_DECLARESQLCOLUMNTYPES_INCLUDED + +#ifdef _MSC_VER +#include <tuple> +#include <array> +#else +#include <tuple> +#include <array> +#endif + + +/** + * @def CPPLOG_DECLARE_SQL_COLUMN_TYPES + * @brief This macro creates an array of SQL types matching an info type list + * @param PP_InfoListName Type name of the info type list + * @param PP_ArrayName Name of the array of SQL data types to be created + * + * The automatic extraction of info data from @c Record objects is based on + * iterating over info type lists. Writing into a database requires, however, + * that table columns have suitable SQL types that can stores the data + * transported by an info type. This macro is provided for the comfortable + * creation of SQL table definitions simply by iterating over the info type + * list and an array of matching column types, which is created by this macro. + * + * @see CPPLOG_DECLARE_INFO_TYPE_LIST + */ +#define CPPLOG_DECLARE_SQL_COLUMN_TYPES( PP_InfoListName, PP_ArrayName, ... ) \ + std::array< std::string, std::tuple_size< PP_InfoListName >::value > \ + PP_ArrayName = {{ __VA_ARGS__ }}; + +#endif /* LOG_DECLARESQLCOLUMNTYPES_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/Enable.h b/odemx-lite/external/CppLog/include/CppLog/Enable.h new file mode 100644 index 0000000000000000000000000000000000000000..5074930b23c26b010200d7fd698b8531ea24dcbd --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/Enable.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Enable.h + * @author Ronald Kluth + * @date 2010/04/24 + * @brief Declaration and implementation of class template Enable + * @since 0.1 + */ + +#ifndef LOG_ENABLE_INCLUDED +#define LOG_ENABLE_INCLUDED + +#include "detail/ChannelField.h" +#include "detail/InheritFields.h" + +namespace Log { + +namespace Detail { enum { UNUSED = -100 }; } + +/** + * @brief Allows enabling of Producer channel members by providing declared channel IDs + * @note The unused IDs will match the general template of ChannelField, which + * becomes an empty class. Only IDs declared with CPPLOG_DECLARE_CHANNEL + * provide a specialization of ChannelField to be derived from. + * @note Declared IDs should not be negative numbers. The numbers for unused + * channels must be different so we do not derive from the same class twice. + */ +template < + int ID0, + int ID1 = Detail::UNUSED-1, + int ID2 = Detail::UNUSED-2, + int ID3 = Detail::UNUSED-3, + int ID4 = Detail::UNUSED-4, + int ID5 = Detail::UNUSED-5, + int ID6 = Detail::UNUSED-6, + int ID7 = Detail::UNUSED-7, + int ID8 = Detail::UNUSED-8, + int ID9 = Detail::UNUSED-9 + > +struct Enable +{ + typedef Detail::InheritFields< + Detail::ChannelField< ID0 >, + Detail::ChannelField< ID1 >, + Detail::ChannelField< ID2 >, + Detail::ChannelField< ID3 >, + Detail::ChannelField< ID4 >, + Detail::ChannelField< ID5 >, + Detail::ChannelField< ID6 >, + Detail::ChannelField< ID7 >, + Detail::ChannelField< ID8 >, + Detail::ChannelField< ID9 > + > + Type; +}; + +} // namespace Log + +#endif /* LOG_ENABLE_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/Filter.h b/odemx-lite/external/CppLog/include/CppLog/Filter.h new file mode 100644 index 0000000000000000000000000000000000000000..bfa3ea69eda84096815954fbdfa9f7035d772993 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/Filter.h @@ -0,0 +1,199 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Filter.h + * @author Ronald Kluth + * @date created at 2009/06/07 + * @brief Declaration and implementation of class Filter + * @since 0.1 + */ + +#ifndef LOG_FILTER_INCLUDED +#define LOG_FILTER_INCLUDED + +#include "StringLiteral.h" +#include "detail/InfoTypeFilter.h" +#include "detail/SetInserter.h" +#include "detail/TypeInfo.h" + +#include <map> + +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +namespace Log { + +// forward declaration +class Record; + +/** + * @brief Basic class template for log filters + * @note If this template is instantiated and @c pass is called, an assertion + * will fail because for each record type a specialization is required. + */ +template < typename RecordT = Record > +class Filter +{ +public: + bool pass( const RecordT& record ) const + { + assert( false && "Missing template specialization for record type" ); + return false; + } +}; + +/** + * @brief A simple filter for log records, based on their text and info type values + * + * This class provides a simple filter for log records. It allows for record + * filtering by comparing each record's info type values to those stored in + * filter sets. All log channels have a member that may hold a record filter, + * but filter objects may be owned and used by log consumers as well to filter + * the records they receive. + * + * @b Usage: + * @code + * std::shared_ptr< Log::Filter< Record > > filter( new Log::Filter< Record >() ); + * filter->passNone(); + * filter->add< Log::ScopeInfo >() << "foo()" << "main()"; + * @endcode + * + * The above code creates a filter object that allows no records to pass except + * those with scope "foo()" or scope "main()". + */ +template <> +class Filter< Record > +{ +public: + /// Creation via static method + static std::shared_ptr< Filter< Record > > create() + { + return std::shared_ptr< Filter< Record > >( new Filter() ); + } + + /// Reset filter to default values, which effectively disables it + void resetFilter() + { + isSet_ = false; + passAll_ = true; + recordTexts_.clear(); + infoTypeFilters_.clear(); + } + + /// Only filter out the log records matched by the filter + void passAll() + { + isSet_ = true; + passAll_ = true; + } + + /// Filter out all log records except those matched by the filter + void passNone() + { + isSet_ = true; + passAll_ = false; + } + + /// Add record text values to the filter + Detail::SetInserter< StringLiteral > addRecordText() + { + // remember that the filter has been initialized + isSet_ = true; + return Detail::SetInserter< StringLiteral >( recordTexts_ ); + } + + /// Add values of type @c InfoT to the corresponding filter set + template < typename InfoT > + Detail::SetInserter< typename InfoT::ValueType > add() + { + using namespace std; + typedef Detail::InfoTypeFilterImpl< InfoT > FilterType; + + // remember that the filter has been initialized + isSet_ = true; + + // get the shared pointer to a filter or create a new one with op[] + InfoTypeFilterPtr& filter = infoTypeFilters_[ typeid( InfoT ) ]; + + // if the shared pointer is not initialized, do it now + if( ! filter ) + { + filter.reset( new FilterType() ); + } + + // return a set inserter object that can be used with op<< + // TODO: using ValueType might not work for pointer types + return Detail::SetInserter< typename InfoT::ValueType >( + static_pointer_cast< FilterType >( filter )->filterSet_ ); + } + + /// Determine whether the @c record may pass the filter by checking info type sets and evaluating @c passAll_ + bool pass( const Record& record ) const + { + // let all records pass if the filter is not set + if( ! isSet_ ) + { + return true; + } + + // check the record text first + if( recordTexts_.find( record.getText() ) != recordTexts_.end() ) + { + // match found, the record may only pass if passAll_ is false + return ! passAll_; + } + + // check all info type filters for matches in this record + bool found = false; + InfoTypeFilterMap::const_iterator iter; + for( iter = infoTypeFilters_.begin(); + iter != infoTypeFilters_.end(); ++iter ) + { + found = iter->second->matches( record ); + if( found ) + { + // match found, the record may only pass if passAll_ is false + return ! passAll_; + } + } + // no match found, the record may pass if passAll_ is true + return passAll_; + } + +protected: + /// Pointer type to manage info type filter objects + typedef std::shared_ptr< Detail::InfoTypeFilter > InfoTypeFilterPtr; + /// Map type that holds smart pointers to info type filters, indexed by type info + typedef std::map< Detail::TypeInfo, InfoTypeFilterPtr > InfoTypeFilterMap; + + /// Stores whether the filter has been initialized with filter values + bool isSet_; + /// Stores whether the filter should by default pass all records or none + bool passAll_; + /// Stores text values to be matched when filtering records + std::set< StringLiteral > recordTexts_; + /// Stores the actual filter objects for different record info types + InfoTypeFilterMap infoTypeFilters_; + +protected: + /// Construction protected, use create instead + Filter() + : isSet_( false ) + , passAll_( true ) + , recordTexts_() + , infoTypeFilters_() + { + } +}; + +} // namespace Log + +#endif /* LOG_FILTER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/NameScope.h b/odemx-lite/external/CppLog/include/CppLog/NameScope.h new file mode 100644 index 0000000000000000000000000000000000000000..0885b54d5b5671ddc5e6779575253bafc7f51ee9 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/NameScope.h @@ -0,0 +1,105 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file NameScope.h + * @author Ronald Kluth + * @date created at 2009/02/08 + * @brief Declaration and implementation of class NameScope + * @since 0.1 + */ + +#ifndef LOG_NAMESCOPE_INCLUDED +#define LOG_NAMESCOPE_INCLUDED + +#include <cstddef> // size_t +#include <map> +#include <sstream> +#include <string> + +namespace Log { + +/** + * @class NameScope + * @brief This class provides a scope for object names. + * + * All named objects receive their name from a name scope. This guarantees + * that every name created by it is unique within the scope. + */ +class NameScope +{ +public: + /** + * @brief Construction + * @param defaultName The default name, given to objects which don't request + * a specific name + * @param defaultSpace The default fill character separating the added number + * from the name string + */ + NameScope( const std::string& defaultName = "Unnamed", const char defaultSpace = '_' ); + + /// Destruction + virtual ~NameScope(); + + /** + * @brief Create a unique name for the caller + * @param name The basic part of the name, if left blank the default + * name is used + * @return A unique name string + * + * This method builds a unique name. If there is already a name in this + * scope equal to the requested @c name, the new name gets a number. + */ + std::string createUniqueName( std::string name ); + +protected: + /// Holds the default name + const std::string defaultName_; + /// Holds the default fill character + const char defaultSpace_; + /// Holds requested names and their number of occurrences within the scope + std::map< std::string, std::size_t > nameLookup_; +}; + +//------------------------------------------------------construction/destruction + +inline NameScope::NameScope( const std::string& defaultName, const char defaultSpace ) +: defaultName_( defaultName ) +, defaultSpace_( defaultSpace ) +{ +} + +inline NameScope::~NameScope() +{ +} + +//---------------------------------------------------------unique label creation + +inline std::string NameScope::createUniqueName( std::string name ) +{ + if( name.empty() ) + { + name = defaultName_; + } + + // get count for this name and increment + unsigned int number = nameLookup_[ name ]++; + + // append count if the name is not unique + if( number > 0 ) + { + std::ostringstream stream; + stream << name << defaultSpace_ << number; + return stream.str(); + } + + return name; +} + +} // namespace Log + +#endif /* LOG_NAMESCOPE_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/NamedElement.h b/odemx-lite/external/CppLog/include/CppLog/NamedElement.h new file mode 100644 index 0000000000000000000000000000000000000000..559d419eeec36c6aec07916a9d09d9ad0a699df7 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/NamedElement.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file NamedElement.h + * @author Ronald Kluth + * @date created at 2009/02/08 + * @brief Declaration and implementation of class NamedElement + * @since 0.1 + */ + +#ifndef LOG_NAMEDELEMENT_INCLUDED +#define LOG_NAMEDELEMENT_INCLUDED + +#include "NameScope.h" +#include <string> + +namespace Log { + +/** + * @class NamedElement + * @brief The base class for all classes whose instances require unique names + * within a name scope + */ +class NamedElement +{ +public: + /** + * @brief Construction with scope and name initialization + * + * The constructor requests the use of @c name from the scope object. The + * value of @c name provides the base for the actual name of the object + * because the scope object may need to append a suffix to ensure the + * uniqueness of names. + */ + NamedElement( NameScope& scope, const std::string& name ); + + /// Destruction + virtual ~NamedElement(); + + /// Get the object's name + const std::string& getName() const; + +private: + /// The name of an object + std::string name_; +}; + +//------------------------------------------------------construction/destruction + +inline NamedElement::NamedElement( NameScope& scope, const std::string& name ) +{ + name_ = scope.createUniqueName( name ); +} + +inline NamedElement::~NamedElement() +{ +} + +//-----------------------------------------------------------------------getters + +inline const std::string& NamedElement::getName() const +{ + return name_; +} + +} // namespace Log + +#endif /* LOG_NAMEDELEMENT_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/Producer.h b/odemx-lite/external/CppLog/include/CppLog/Producer.h new file mode 100644 index 0000000000000000000000000000000000000000..13d1e785472ee1073bfc5a14964397628085faee --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/Producer.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file CppLog/Producer.h + * @author Ronald Kluth + * @date created at 2009/06/06 + * @brief Declaration and implementation of class template Producer + * @since 0.1 + */ + +#ifndef LOG_PRODUCER_INCLUDED +#define LOG_PRODUCER_INCLUDED + +#include "ChannelManager.h" +#include "Enable.h" +#include "NamedElement.h" + +namespace Log { + +/** + * @brief Producer template type, ensures that all producers have unique names + * @tparam EnableT The type of channels to be enabled for the producer + * + * The producer will automatically contain pointers to enabled channels, but + * these are not initialized. This is the responsibility of the subclass. + */ +template < typename EnableT > +class Producer +: public NamedElement +, public EnableT::Type +{ +public: + /** + * @brief Construction + * @param scope Reference to the name scope which ensures unique names + * @param name Name of the log producer object, unique within the given scope + */ + Producer( NameScope& scope, std::string const& name ) + : NamedElement( scope, name ) + {} + + /** + * @brief Construction with channel manager + * @param manager Reference to a channel manager + * @param name Name of the log producer object, unique within manager's scope + * @note This constructor can only be used if all of the producer's channels + * use the same record type, because the enabled channels are automatically + * initialized during construction + */ + template < typename RecordT > + Producer( ChannelManager< RecordT >& manager, std::string const& name ) + : NamedElement( manager, name ) + , EnableT::Type( manager ) + {} + + /// Destruction + virtual ~Producer() {} + +private: + /// Non-copyable + Producer( Producer const& ); + /// Non-assignable + Producer& operator=( Producer const& ); +}; + +} // namespace Log + +#endif /* LOG_PRODUCER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/Record.h b/odemx-lite/external/CppLog/include/CppLog/Record.h new file mode 100644 index 0000000000000000000000000000000000000000..60390bd59c1b1e00254b3271e5a717766668e0d9 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/Record.h @@ -0,0 +1,149 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Record.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration and implementation of class Record + * @since 0.1 + */ + +#ifndef LOG_RECORD_INCLUDED +#define LOG_RECORD_INCLUDED + +#include "DeclareInfoType.h" +#include "StringLiteral.h" +#include "detail/InfoHolder.h" +#include "detail/InfoTypeLoop.h" + +namespace Log { + +/** + * @struct FileInfo + * @brief Record info type that holds filenames as @c std::string + */ +#ifndef DOXYGEN_SKIP +CPPLOG_DECLARE_INFO_TYPE( FileInfo, "file", StringLiteral ); +#endif + +/** + * @struct LineInfo + * @brief Record info type that holds line numbers as <tt>unsigned int</tt> + */ +#ifndef DOXYGEN_SKIP +CPPLOG_DECLARE_INFO_TYPE( LineInfo, "line", unsigned int ); +#endif + +/** + * @struct ScopeInfo + * @brief Record info type that holds scope information as @c std::string + */ +#ifndef DOXYGEN_SKIP +CPPLOG_DECLARE_INFO_TYPE( ScopeInfo, "scope", StringLiteral ); +#endif + +/** + * @brief The default record type provided by the library + * + * Objects of this class transport information passed through log channels + * + * By deriving from InfoHolder, record objects gain the ability to transport + * information of arbitrary type. All that is needed to use the feature are + * simple macro calls which declare the used information types. + * + * @code + * CPPLOG_DECLARE_INFO_TYPE( SenderInfo, "Sender", std::string ); + * @endcode + * + * After this, the declared type can already be used to add more information + * to log records. Usage of this feature is implemented through an overloaded + * @c operator+. The stored information can be retrieved by calling the method + * template @c get, which is defined in the base class InfoHolder. The template + * parameter is the information type. + * + * @code + * Record rec( "log message" ); + * rec + SenderInfo( "class XYZ" ); + * + * if( SenderInfo::ValueType* sender = rec.get< SenderInfo >() ) + * { + * std::cout << *sender; + * } + * @endcode + * + * The library by default provides three info types for log records: + * @c FileInfo, @c LineInfo, and @c ScopeInfo. Class Record provides chainable + * convenience methods to easily add these types. They can be used like this: + * + * @code + * Log::Record rec( "message text" ); + * rec.file( __FILE__ ).line( __LINE__ ).scope( "foo()" ); + * @endcode + */ +class Record +: public Detail::InfoHolder< Record > +{ +public: + /// Default construction + Record() {} + + /// Construction with text message + Record( const StringLiteral& text ) + : text_( text ) + {} + + /// Destruction + virtual ~Record() {} + + /// Add file information to the record, supports method chaining + Record& file( const StringLiteral& file ) + { + *this + FileInfo( file ); + return *this; + } + + /// Add line information to the record, supports method chaining + Record& line( const unsigned int lineNumber ) + { + *this + LineInfo( lineNumber ); + return *this; + } + + /// Add scope information to the record, supports method chaining + Record& scope( const StringLiteral& scope ) + { + *this + ScopeInfo( scope ); + return *this; + } + /// Get the text message sent with the log record + const StringLiteral& getText() const + { + return text_; + } + + /// Call @c func on the record object for all listed info types and return @c func + template < typename InfoListT, typename FuncT > + FuncT& iterateInfo( FuncT& func ) const + { + Detail::InfoTypeLoop< + FuncT, + Record, + InfoListT, + Detail::SizeOf< InfoListT >::value - 1 + >::call( func, *this ); + return func; + } + +private: + /// Stores the message text transported by a record + StringLiteral text_; +}; + +} // namespace Log + +#endif /* LOG_RECORD_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/StringLiteral.h b/odemx-lite/external/CppLog/include/CppLog/StringLiteral.h new file mode 100644 index 0000000000000000000000000000000000000000..1949e32c3d05d15216b6b4bf0dd9f2a18445f8ba --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/StringLiteral.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file StringLiteral.h + * @author Ronald Kluth + * @date created at 2009/11/19 + * @brief Declaration of type StringLiteral + * @since 0.1 + */ + +#ifndef LOG_STRINGLITERAL_INCLUDED +#define LOG_STRINGLITERAL_INCLUDED + +#include "detail/string_literal.hpp" + +namespace Log { + +/** + * @typedef StringLiteral + * @brief Thin wrapper around string literals, borrowed from boost::log + * + * This class provides a thin wrapper around string literals (i.e. "strings like this") + * with the const method interface of @c std::string. All member data are + * allocated on the stack, making it significantly faster than @c std::string. + * It can be contructed with or without a string literal, and the class offers + * assignment, clearing, and comparison operators. Explicit conversion to std::string + * and C-strings ist provided as well. Use in containers is possible. + */ +typedef boost::log::string_literal StringLiteral; + +} // namespace Log + +#endif /* LOG_STRINGLITERAL_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/Bindings.h b/odemx-lite/external/CppLog/include/CppLog/detail/Bindings.h new file mode 100644 index 0000000000000000000000000000000000000000..546eeb9898a92666c2c9c0dd482e052af012fe54 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/Bindings.h @@ -0,0 +1,144 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Bindings.h + * @author Ronald Kluth + * @date 2009/11/28 + * @brief Implementation of template specialization Poco::Data::Binding<boost::log::string_literal> + * @since 0.1 + */ + +#ifndef LOG_DETAIL_BINDINGS_INCLUDED +#define LOG_DETAIL_BINDINGS_INCLUDED + +#include "string_literal.hpp" + +#include <Poco/Data/Binding.h> + +namespace Poco { +namespace Data { + +/** + * @brief Template specialization for database insertion of boost::log::string_literal + */ +template <> +class Binding< boost::log::string_literal >: public AbstractBinding + /// Binding const char* specialization wraps char pointer into string. +{ +public: + explicit Binding( const boost::log::string_literal& pVal, + const std::string& name = "", + Direction direction = PD_IN): + AbstractBinding(name, direction), + _val( pVal.c_str() ), + _bound(false) + /// Creates the Binding by copying the passed string. + { + } + + ~Binding() + /// Destroys the Binding. + { + } + + std::size_t numOfColumnsHandled() const + { + return 1u; + } + + std::size_t numOfRowsHandled() const + { + return 1u; + } + + bool canBind() const + { + return !_bound; + } + + void bind(std::size_t pos) + { + poco_assert_dbg(getBinder() != 0); + TypeHandler<std::string>::bind(pos, _val, getBinder(), getDirection()); + _bound = true; + } + + void reset () + { + _bound = false; + AbstractBinder* pBinder = getBinder(); + poco_check_ptr (pBinder); + pBinder->reset(); + } + +private: + std::string _val; + bool _bound; +}; + +/** + * @brief Template specialization for database insertion of boost::log::string_literal + */ +template <> +class CopyBinding< boost::log::string_literal >: public AbstractBinding + /// Binding const char* specialization wraps char pointer into string. +{ +public: + explicit CopyBinding( const boost::log::string_literal& pVal, + const std::string& name = "", + Direction direction = PD_IN): + AbstractBinding(name, direction), + _val( pVal.c_str() ), + _bound(false) + /// Creates the Binding by copying the passed string. + { + } + + ~CopyBinding() + /// Destroys the Binding. + { + } + + std::size_t numOfColumnsHandled() const + { + return 1u; + } + + std::size_t numOfRowsHandled() const + { + return 1u; + } + + bool canBind() const + { + return !_bound; + } + + void bind(std::size_t pos) + { + poco_assert_dbg(getBinder() != 0); + TypeHandler<std::string>::bind(pos, _val, getBinder(), getDirection()); + _bound = true; + } + + void reset () + { + _bound = false; + AbstractBinder* pBinder = getBinder(); + poco_check_ptr (pBinder); + pBinder->reset(); + } + +private: + std::string _val; + bool _bound; +}; + +} } // namespace Poco::Data + +#endif /* LOG_DETAIL_BINDINGS_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/ChannelField.h b/odemx-lite/external/CppLog/include/CppLog/detail/ChannelField.h new file mode 100644 index 0000000000000000000000000000000000000000..221bbaf30bffdd26a951b419d853e18dca38fb76 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/ChannelField.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file ChannelField.h + * @author Ronald Kluth + * @date created at 2009/11/05 + * @brief Declaration of class template ChannelField + * @since 0.1 + */ + +#ifndef LOG_CHANNELFIELD_INCLUDED +#define LOG_CHANNELFIELD_INCLUDED + +#include "../ChannelManager.h" + +namespace Log { +namespace Detail { + +/** + * @brief Class template for adding producer channel members, default is empty + * + * This template is used by the macro @c CPPLOG_DECLARE_CHANNEL, which defines + * specializations containing a named channel pointer member. These + * specializations are then inherited to add channel members to producers. + */ +template < int ID > +struct ChannelField +{ + ChannelField(){} + template< typename ManagerT > + ChannelField( ManagerT& ignored ){} +}; + +} } // namespace Log::Detail + +#endif /* LOG_CHANNELFIELD_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/DebugOut.h b/odemx-lite/external/CppLog/include/CppLog/detail/DebugOut.h new file mode 100644 index 0000000000000000000000000000000000000000..4a77daee8827058b844d49aedd9732b7749c289e --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/DebugOut.h @@ -0,0 +1,63 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file DebugOut.h + * @author Ronald Kluth + * @date created at 2009/11/25 + * @brief Declaration and implementation of class DebugOut and stream inserter + * @since 0.1 + */ + +#ifndef LOG_DETAIL_DEBUGOUT_INCLUDED +#define LOG_DETAIL_DEBUGOUT_INCLUDED + +#include <iostream> +#include <string> + +namespace Log { +namespace Detail { + +/** + * @brief Helper struct to quickly add scoped stdout debugging + * + * When an object of this type is declared with its scope given as string, + * it will print 'entering scope' upon construction and 'leaving scope' upon + * destruction. During its lifetime, the object can then be used like an + * @c std::ostream to print arbitrary data to stdout. + */ +struct DebugOut +{ + DebugOut( const std::string& scope ): scope_( scope ) + { + std::cout << "entering " << scope_ << std::endl; + } + ~DebugOut() + { + std::cout << "leaving " << scope_ << std::endl; + } + std::string scope_; +}; + +/** + * @brief Overload of the stream inserter op<< for DebugOut and arbitrary values + * @tparam T Type of the value to be printed to @c stdout + * @param out Reference to the DebugOut object + * @param t Value to be printed to @c stdout + * @return @c out to enable chaining + */ +template < typename T > +const DebugOut& operator<<( const DebugOut& out, const Strip<T>::Ref t ) +{ + // shortcut to cout + std::cout << t << std::flush; + return out; +} + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_DEBUGOUT_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/EnableIf.h b/odemx-lite/external/CppLog/include/CppLog/detail/EnableIf.h new file mode 100644 index 0000000000000000000000000000000000000000..a727d07965ca1f3216a4b329c602030a58217d4b --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/EnableIf.h @@ -0,0 +1,54 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file EnableIf.h + * @author Ronald Kluth + * @date created at 2009/11/25 + * @brief Declaration and implementation of class template EnableIf + * @since 0.1 + */ + +#ifndef LOG_DETAIL_ENABLEIF_INCLUDED +#define LOG_DETAIL_ENABLEIF_INCLUDED + +namespace Log { +namespace Detail { + +/** + * @brief EnableIf implementation, matches @c true, has @c Type definition + */ +template < bool B, typename T = void > +struct EnableIfImpl +{ + typedef T Type; +}; + +/** + * @brief EnableIf implementation, @c false specialization, has no @c Type definition + */ +template < typename T > +struct EnableIfImpl< false, T > +{ +}; + +/** + * @brief Enables templates by checking a condition (e.g. using type traits) + * @note This technique is based on boost::enable_if + * @see InfoType + * + * This template is used to select template specializations, for example by + * checking type traits such as @c is_pointer or @c is_reference. + */ +template < typename Cond, typename T = void > +struct EnableIf: public EnableIfImpl< Cond::value, T > +{ +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_ENABLEIF_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/InfoHolder.h b/odemx-lite/external/CppLog/include/CppLog/detail/InfoHolder.h new file mode 100644 index 0000000000000000000000000000000000000000..d96efeb3bc6a8e3cd4a29f3a53e18361dd4e3c0d --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/InfoHolder.h @@ -0,0 +1,137 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file InfoHolder.h + * @author Ronald Kluth + * @date created at 2009/05/28 + * @brief Declaration and implementation of class template InfoHolder + * @since 0.1 + */ + +#ifndef LOG_DETAIL_INFOHOLDER_INCLUDED +#define LOG_DETAIL_INFOHOLDER_INCLUDED + +#include "TypeInfo.h" + +#include <cassert> +#include <map> + +#ifdef _MSC_VER +#include <memory> +#include <unordered_map> +#else +#include <memory> +#include <unordered_map> +#endif + +namespace Log { +namespace Detail { + +// forward declarations +class InfoTypeBase; +template < typename, typename , typename > class InfoType; + +/** + * @class InfoHolder + * @brief Base class that allows storage of any number of InfoType objects + * + * This class allows the storage of arbitrary data objects, they are + * instances of InfoType classes or one if their subclasses. It works by + * keeping a map of TypeInfo and InfoTypeBase objects. The actual InfoType + * value is accessed by a templated method that must provide the real type + * in order to retrieve it from the map by looking up the @c typeid. + * + * @note InfoType and InfoHolder are based on a technique demonstrated + * by boost::error_info. + */ +template < typename DerivedT > +class InfoHolder +{ +public: + // NOTE: using InfoTypeBase const* as map value would require InfoHolder + // to be non-copyable to avoid multiple deletion in the destructor, + // another (inefficient) option would be deep copying of the map + + typedef DerivedT DerivedType; + + /// Map type to hold pointers to InfoType objects, indexed by their TypeInfo +// typedef std::map< TypeInfo, std::shared_ptr< InfoTypeBase const > > InfoMap; + typedef std::unordered_map< TypeInfo, std::shared_ptr< InfoTypeBase const > > InfoMap; + + // Compiler-generated ctor, copy, and assignment is o.k. + + /// Destruction + virtual ~InfoHolder() {} + + /// Overloaded @c operator+ provides the means to add InfoType objects to InfoHolder + template < typename InfoT > + friend + DerivedType const& + operator+( DerivedType const& holder, InfoT const& value ) + { + // copy-construct a dynamically allocated Info object from value + // and store it in a base class pointer + std::shared_ptr< InfoTypeBase const > data( new InfoT( value ) ); + holder.add( data, typeid( InfoT ) ); + return holder; + } + + /// Retrieval of InfoType objects via template method, @c InfoT must be specified + template < typename InfoT > + typename InfoT::Type const* + get() const + { + typedef InfoT Info; + + std::shared_ptr< InfoTypeBase const > const& + basePtr = getInfoByType( typeid( Info ) ); + + // the returned basePtr object may be empty if type not found + if( ! basePtr ) + { + return 0; + } + + // retrieve the actual info type and return its value + Info const* data = static_cast< Info const* >( basePtr.get() ); + return data->value(); + } + +private: + // HACK: declared mutable to allow use of const temporaries with op+ above + /// Internal InfoType object storage, indexed by TypeInfo + mutable InfoMap infos_; + +private: + /// Internal method to add an InfoType object to the InfoHolder + void add( std::shared_ptr< InfoTypeBase const > const& data, + TypeInfo const& typeInfo ) const + { + //assert( data ); + // existing entries will be replaced and automatically deleted + infos_[ typeInfo ] = data; + } + + /// Internal method for retrieval of a stored InfoType object + std::shared_ptr< InfoTypeBase const > const& + getInfoByType( TypeInfo const& typeInfo ) const + { + InfoMap::const_iterator found = infos_.find( typeInfo ); + if( found != infos_.end() ) + { + return found->second; + } + // this allows us to always return a reference + static std::shared_ptr< InfoTypeBase const > const emptyPtr; + return emptyPtr; + } +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_INFOHOLDER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/InfoType.h b/odemx-lite/external/CppLog/include/CppLog/detail/InfoType.h new file mode 100644 index 0000000000000000000000000000000000000000..bfe1570f61139b819e17b6283c489c8ee80ef302 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/InfoType.h @@ -0,0 +1,194 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file InfoType.h + * @author Ronald Kluth + * @date created at 2009/05/28 + * @brief Declaration and implementation of class template InfoType + * @since 0.1 + */ + +#ifndef LOG_DETAIL_INFOTYPE_INCLUDED +#define LOG_DETAIL_INFOTYPE_INCLUDED + +#include "EnableIf.h" +#include "Strip.h" +#include "string_literal.hpp" + +#ifdef _MSC_VER +#include <type_traits> +#else +#include <type_traits> +#endif + +#include <string> + +namespace Log { +namespace Detail { + +typedef boost::log::string_literal StringLiteral; + +/** + * @class InfoTypeBase + * @brief Empty base class used to emulate heterogeneous containers + * + * This class is used to allow storage of pointers to different @c InfoType<T> + * objects in containers. The real value is retrieved by using template methods + * parameterized with the correct info type. + * + * @see InfoType, InfoHolder + */ +class InfoTypeBase +{ +public: + virtual ~InfoTypeBase() {} +}; + +/** + * @class InfoType + * @brief Wrapper for arbitrary value types to store additional record information + * @tparam NameHolderT Unique type to distinguish info types and get a string name + * @tparam ValueT Type of the wrappper's stored value, must be copyable + * @tparam EnableT Specialization selector, e.g. @c EnableIf<> + * @note The default template implementation copies the value. + * + * Info type classes can hold arbitrary data of type @c ValueT. The tag type + * @c TagT is required to distinguish info type objects with the same value + * type by using their @c typeid. Obviously, the tag types must be unique for + * this to work properly. + * + * @note InfoType and InfoHolder are based on a technique demonstrated + * by boost::error_info. + * @note This class template is not intended to be used directly, use the macro + * @c CPPLOG_DECLARE_INFO_TYPE instead. + */ +template < typename NameHolderT, typename ValueT, typename EnableT = void > +class InfoType +: public InfoTypeBase +{ +public: + /// Type of the struct providing the info type's string name + typedef NameHolderT NameHolderType; + /// Value type definition for template use and value access + typedef ValueT ValueType; + /// Actual type of the data, when pointer or reference is stripped + typedef typename Strip< ValueType >::Type Type; + + /// Construction + InfoType( Type const& value ) + : value_( value ) + { + } + + /// Value retrieval + Type const* value() const + { + return &value_; + } + + /// Get a string name for this info type + static StringLiteral const& getName() + { + return NameHolderType::getName(); + } + +private: + /// Const value storage, no re-assignment + Type const value_; +}; + +#ifndef DOXYGEN_SKIP +/** + * @brief Specialization of InfoType to hold pointer types + * @note This specialization only copies the pointer, not the value. + * @note The fact that the method @c value always returns a pointer to const + * allows @c InfoHolder::get to always return a pointer, instead of pointer-to-pointer. + */ +#endif +template < typename NameHolderT, typename ValueT > +class InfoType< NameHolderT, ValueT, typename EnableIf< typename std::is_pointer< ValueT > >::Type > +: public InfoTypeBase +{ +public: + /// Type of the struct providing the info type's string name + typedef NameHolderT NameHolderType; + /// Value type definition for template use and value access + typedef ValueT ValueType; + /// Actual type of the data, when pointer or reference is stripped + typedef typename Strip< ValueType >::Type Type; + + /// Construction + InfoType( Type const* value ) + : value_( value ) + { + } + + /// Value retrieval + Type const* value() const + { + return value_; + } + + /// Get a string name for this info type + static StringLiteral const& getName() + { + return NameHolderType::getName(); + } + +private: + /// Const value storage, no re-assignment + Type const* value_; +}; + +#ifndef DOXYGEN_SKIP +/** + * @brief Specialization of InfoType to hold reference types + * @note The specialization only copies the reference, not the value + * @note The fact that the method @c value always returns a pointer to const + * allows @c InfoHolder::get to always return a pointer, instead of + * pointer-to-reference (which is not allowed). + */ +#endif +template < typename NameHolderT, typename ValueT > +class InfoType< NameHolderT, ValueT, typename EnableIf< typename std::is_reference< ValueT > >::Type > +: public InfoTypeBase +{ +public: + /// Type of the struct providing the info type's string name + typedef NameHolderT NameHolderType; + /// Value type definition for template use and value access + typedef ValueT ValueType; + /// Actual type of the data, when pointer or reference is stripped + typedef typename Strip< ValueType >::Type Type; + + /// Construction + InfoType( Type const& value ) + : value_( value ) + { + } + + /// Value retrieval + Type const* value() const + { + return &value_; + } + + /// Get a string name for this info type + static StringLiteral const& getName() + { + return NameHolderType::getName(); + } + +private: + /// Const value storage, no re-assignment + Type const& value_; +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_INFOTYPE_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/InfoTypeFilter.h b/odemx-lite/external/CppLog/include/CppLog/detail/InfoTypeFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..a914692a1a54eebd4f2281005be5331b9dd6c761 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/InfoTypeFilter.h @@ -0,0 +1,85 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file InfoTypeFilter.h + * @author Ronald Kluth + * @date created at 2009/06/07 + * @brief Declaration and implementation of class InfoTypeFilter and template InfoTypeFilterImpl + * @since 0.1 + */ + +#ifndef LOG_DETAIL_INFOTYPEFILTER_INCLUDED +#define LOG_DETAIL_INFOTYPEFILTER_INCLUDED + +#include "../Record.h" + +#include <set> + +namespace Log { +namespace Detail { + +/** + * @class InfoTypeFilter + * @brief Interface class to emulate hetrogeneous containers + * + * A record filter holds a map of info type filters. In order to check records + * for filtering, the record filter iterates over all InfoTypeFilter objects + * and checks whether one of the stored values matches that stored in the record. + */ +class InfoTypeFilter +{ +public: + /// Destruction + virtual ~InfoTypeFilter() {} + /// Called on derived objects that store sets of InfoType values + virtual bool matches( const Record& record ) = 0; +}; + +/** + * @class InfoTypeFilterImpl + * @brief Implementation of record filtering functionality based on info types + * @tparam InfoT Type of record info to be filtered + * + * The implementation of InfoTypeFilter holds a set of @c InfoT values to be + * matched against those transported by records. This class defines the method + * @c matches, which determines whether a given record contains an info + * type value that is stored in the filter set. + */ +template < typename InfoT > +class InfoTypeFilterImpl +: public InfoTypeFilter +{ +public: + /// The record info type that can be filtered by this class + typedef InfoT InfoType; + /// Set type to hold filter values + typedef std::set< typename InfoType::ValueType > FilterSet; + + /// Destruction + virtual ~InfoTypeFilterImpl() {} + + /// Check if the @c InfoT value of @c record is found in the filter set + virtual bool matches( const Record& record ) + { + // try to retrieve the InfoType value from the record, may be 0 + typename InfoType::ValueType const* value = record.get< InfoType >(); + if( ! value ) + { + return false; + } + // a record matches if the value is found in the filter set + return filterSet_.find( *value ) != filterSet_.end(); + } + + /// Stores @c InfoT values to determine which records get filtered out + FilterSet filterSet_; +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_INFOTYPEFILTER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/InfoTypeLoop.h b/odemx-lite/external/CppLog/include/CppLog/detail/InfoTypeLoop.h new file mode 100644 index 0000000000000000000000000000000000000000..247529ad9bcc17db4add0d45650be38498d35332 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/InfoTypeLoop.h @@ -0,0 +1,178 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file InfoTypeLoop.h + * @author Ronald Kluth + * @date created at 2009/06/09 + * @brief Declaration and implementation of class template InfoTypeLoop, + * SizeOf and TypeOf for tuples + * @since 0.1 + */ + +#ifndef LOG_DETAIL_INFOTYPELOOP_INCLUDED +#define LOG_DETAIL_INFOTYPELOOP_INCLUDED + +#ifdef _MSC_VER +#include <tuple> +#else +#include <tuple> +#endif + + +namespace Log { +namespace Detail { + +/** + * @brief Class type to represent empty type lists + * + * This empty class is used as default template parameter for default + * output components. It is needed in case the logged records do not contain + * any info types to extract. Extraction of a NullList stops the InfoTypeLoop + * and therefore does nothing. + */ +struct NullList {}; + +/** + * @class SizeOf + * @brief Determine the number types of an info type list + * @tparam InfoListT A list of info types (must be an @c std::tuple) + * + * This class provides a wrapper over @c std::tuple_size to determine + * the number of types in @c InfoListT at compile time. + */ +template < typename InfoListT > +struct SizeOf +{ + enum { value = std::tuple_size< InfoListT >::value }; +}; + +#ifndef DOXYGEN_SKIP +/// Template specialization for @c NullList +#endif +template<> +struct SizeOf< NullList > +{ + enum { value = 0 }; +}; + +/** + * @class TypeOf + * @brief Determine the type of an element in a list of info types + * @tparam InfoListT A list of info types + * @tparam Index The index of the element whose type is to be determined + * + * This class provides a wrapper over @c std::tuple_element to determine + * the type of the @c InfoListT type at position @c Index + */ +template < typename InfoListT, int Index > +struct TypeOf +{ + typedef typename std::tuple_element< Index, InfoListT >::type type; +}; + +#ifndef DOXYGEN_SKIP +/// Template specialization for @c NullList +#endif +template < int Index > +struct TypeOf< NullList, Index > +{ +}; + +/** + * @class InfoTypeLoop + * @brief Loop type used to iterate over an info type list + * @tparam FuncT A functor type to be called for each info type + * @tparam InfoHolderT A type that allows transporting arbitrary info type data + * @tparam InfoListT A list of info types + * @tparam Index The index of the current recursion in the list + * + * @note The template parameter FuncT must support the follwing signature: + * @code + * template < class InfoT > func( const std::string&, const InfoT& ); + * @endcode + * with @c InfoT being the same as @c InfoHolderT::ValueType. + * + * @see Log::Record::iterateInfo + */ +template < + typename FuncT, + typename InfoHolderT, + typename InfoListT, + int Index +> +struct InfoTypeLoop +{ + static void call( FuncT& func, const InfoHolderT& holder ) + { + // recurse first + InfoTypeLoop< FuncT, InfoHolderT, InfoListT, Index - 1 >::call( func, holder ); + + typedef typename TypeOf< InfoListT, Index >::type CurrentInfo; + typename CurrentInfo::Type const* valuePtr = holder.template get< CurrentInfo >(); + + // call func upon return to keep the correct order + if( valuePtr ) + { + func( CurrentInfo::getName(), *valuePtr, true ); + } + else + { + func( CurrentInfo::getName(), 0, false ); + } + } +}; + +#ifndef DOXYGEN_SKIP +/** + * @brief Template specialization for index 0, terminates the recursion + */ +#endif +template < + typename FuncT, + typename InfoHolderT, + typename InfoListT +> +struct InfoTypeLoop< FuncT, InfoHolderT, InfoListT, 0 > +{ + static void call( FuncT& func, const InfoHolderT& holder ) + { + typedef typename TypeOf< InfoListT, 0 >::type CurrentInfo; + typename CurrentInfo::Type const* valuePtr = holder.template get< CurrentInfo >(); + + // stop recursion, call func( name, value ); + if( valuePtr ) + { + func( CurrentInfo::getName(), *valuePtr, true ); + } + else + { + func( CurrentInfo::getName(), 0, false ); + } + } +}; + +#ifndef DOXYGEN_SKIP +/** + * @brief Template specialization for empty info type list + */ +#endif +template < + typename FuncT, + typename InfoHolderT, + int Index +> +struct InfoTypeLoop< FuncT, InfoHolderT, NullList, Index > +{ + static void call( FuncT& func, const InfoHolderT& holder ) + { + } +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_INFOTYPELOOP_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/InheritFields.h b/odemx-lite/external/CppLog/include/CppLog/detail/InheritFields.h new file mode 100644 index 0000000000000000000000000000000000000000..285325baf30444effb8454be41784bcd90696c89 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/InheritFields.h @@ -0,0 +1,67 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file InheritFields.h + * @author Ronald Kluth + * @date created at 2009/12/17 + * @brief Declaration and implementation of class template InheritFields + * @since 0.1 + */ + +#ifndef LOG_DETAIL_INHERITFIELDS +#define LOG_DETAIL_INHERITFIELDS + +namespace Log { +namespace Detail { + +/** + * @brief Helper class template to inherit from a maximum of 10 ChannelField specializations + */ +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9 + > +struct InheritFields +: public T0 +, public T1 +, public T2 +, public T3 +, public T4 +, public T5 +, public T6 +, public T7 +, public T8 +, public T9 +{ + InheritFields(){} + template< typename ManagerT > + InheritFields( ManagerT& manager ) + : T0( manager ) + , T1( manager ) + , T2( manager ) + , T3( manager ) + , T4( manager ) + , T5( manager ) + , T6( manager ) + , T7( manager ) + , T8( manager ) + , T9( manager ) + {} +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_INHERITFIELDS */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/SetInserter.h b/odemx-lite/external/CppLog/include/CppLog/detail/SetInserter.h new file mode 100644 index 0000000000000000000000000000000000000000..e4a3f9ca7c9895ace7180b2f9230395675182228 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/SetInserter.h @@ -0,0 +1,71 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file SetInserter.h + * @author Ronald Kluth + * @date created at 2009/03/29 + * @brief Declaration and implementation of class template SetInserter + * @since 0.1 + */ + +#ifndef LOG_DETAIL_SETINSERTER_INCLUDED +#define LOG_DETAIL_SETINSERTER_INCLUDED + +#include <set> + +namespace Log { +namespace Detail { + +// forward declaration +template < typename SetInserterT > +const SetInserterT& +operator<<( const SetInserterT& ins, const typename SetInserterT::ValueType& value ); + +/** + * @brief Helper class to enable @c std::set value insertion with @c operator<< + */ +template< typename ValueT > +struct SetInserter +{ + /// Type of the values the inserter can add to a set + typedef ValueT ValueType; + /// Set type to be modified by the inserter object + typedef std::set< ValueType > SetType; + + /// Reference to the set which is to be modified + SetType& set_; + + /// Construction with non-const reference to a set + SetInserter( SetType& set ): set_( set ) {} + + /// Add a value to the referenced @c set_ + const SetInserter& add( const ValueType& value ) const + { + set_.insert( value ); + return *this; + } + + template < typename SetInserterT > + friend + const SetInserterT& + operator<<( const SetInserterT& ins, const typename SetInserterT::ValueType& value ); +}; + +/// Insertion operator to add values to a set in a stream-like manner +template < typename SetInserterT > +inline +const SetInserterT& +operator<<( const SetInserterT& ins, const typename SetInserterT::ValueType& value ) +{ + ins.add( value ); + return ins; +} + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_SETINSERTER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/SqlInserter.h b/odemx-lite/external/CppLog/include/CppLog/detail/SqlInserter.h new file mode 100644 index 0000000000000000000000000000000000000000..11366605c3a4c7628adc5733c415e42e6a8bd4b3 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/SqlInserter.h @@ -0,0 +1,403 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file SqlInserter.h + * @author Ronald Kluth + * @date created at 2009/07/30 + * @brief Declaration and implementation of class SqlInserter + * @since 0.1 + */ + +#ifndef LOG_DETAIL_SQLINSERTER_INCLUDED +#define LOG_DETAIL_SQLINSERTER_INCLUDED + +#include "string_literal.hpp" +#include "Bindings.h" + +#include <Poco/Data/Statement.h> +#include <Poco/Data/StatementImpl.h> +#include <Poco/Data/AbstractBinding.h> + +namespace Log { +namespace Detail { + +/** + * @brief Helper class to build SQL INSERT INTO TABLE statements + */ +class SqlInserter +{ +private: + /// String literal type to wrap C character arrays + typedef boost::log::string_literal StringLiteral; + +/// FIXME Hacking around Poco fixupBinding and bindings being protected. + class LogStatementImpl : public Poco::Data::StatementImpl { + public: + void fixupBinding () { + Poco::Data::StatementImpl::fixupBinding (); + } + + Poco::Data::AbstractBindingVec& bindings() { + return Poco::Data::StatementImpl::bindings(); + } + }; + + class LogStatement: public Poco::Data::Statement { + public: + LogStatement(Poco::Data::Session& session) : Poco::Data::Statement(session) + {} + + void fixupBinding () { + LogStatementImpl& lsi = (LogStatementImpl&) *impl(); + lsi.fixupBinding(); + } + + Poco::Data::AbstractBindingVec& bindings () { + LogStatementImpl& lsi = (LogStatementImpl&) *impl(); + return lsi.bindings(); + } + }; + +public: + /// Construction without table name, to be used with DatabaseAccessor::createInserter + SqlInserter( Poco::Data::Session& session, bool autoExec = false ) + : session_( &session ) + , stmt_( session ) + , executed_( false ) + , autoExec_( autoExec ) + {} + + /// Construction with table name, used for temporary inserter objects + SqlInserter( std::string const& tableName, Poco::Data::Session& session, bool autoExec = false ) + : session_( &session ) + , stmt_( session ) + , tableName_( tableName ) + , executed_( false ) + , autoExec_( autoExec ) + {} + + /// Destruction, executes the statement if necessary + ~SqlInserter() + { + if( ! executed_ && autoExec_ ) + { + execute(); + } + } + + /// Set the table of an inserter object + SqlInserter& table( std::string const& tableName ) + { + executed_ = false; + tableName_ = tableName; + return *this; + } + + /// Add a column and a placeholder to the SQL statement + SqlInserter& column( std::string const& columnName ) + { + executed_ = false; + // add a comma if not the first value + if( ! columnNames_.empty() ) + { + columnNames_.append( 1, ',' ); + placeholders_.append( 1, ',' ); + } + // store the column name and a placeholder + columnNames_.append( columnName ); + placeholders_.append( 1, '?' ); + return *this; + } + + /// Add multiple columns and placeholders, according to the info type list + template < typename InfoListT > + SqlInserter& columns() + { + executed_ = false; + if( SizeOf< InfoListT >::value > 0 ) + { + ColumnLoop< + InfoListT, + SizeOf< InfoListT >::value - 1 + >::call( columnNames_, placeholders_ ); + } + return *this; + } + + /// Bind a value that corresponds to a placeholder in the SQL statement + template < typename ValueT > + SqlInserter& value( ValueT const& val ) + { + executed_ = false; + columnBindings_.push_back( Poco::Data::Keywords::useRef( val ) ); + return *this; + } + + /// Bind multiple values from a Record object that correspond to placeholders + template < typename InfoListT, typename RecordT > + SqlInserter& values( RecordT const& record ) + { + executed_ = false; + ValueAdder addBindings( columnBindings_ ); + record.template iterateInfo< InfoListT >( addBindings ); + return *this; + } + + /// Add a column and a placeholder and bind the given value to it + template < typename ValueT > + SqlInserter& columnValue( std::string const& columnName, ValueT const& val ) + { + executed_ = false; + // add a comma if not the first value + if( ! columnNames_.empty() ) + { + columnNames_.append( 1, ',' ); + placeholders_.append( 1, ',' ); + } + // store the column name and a placeholder + columnNames_.append( columnName ); + placeholders_.append( 1, '?' ); + // store the data + columnBindings_.push_back( Poco::Data::Keywords::useRef( val ) ); + return *this; + } + + /// Add multiple columns and placeholders and bind the Record's stored values to them + template < typename InfoListT, typename RecordT > + SqlInserter& columnValues( RecordT const& record ) + { + executed_ = false; + NameValueAdder addColumns( columnNames_, placeholders_, columnBindings_ ); + record.template iterateInfo< InfoListT >( addColumns ); + return *this; + } + + /// Execute the constructed SQL statement + void execute() + { + // create the SQL command if it has not been constructed yet + if( sql_.empty() ) + { + makeSql(); + stmt_ << sql_; + stmt_.addBinding( columnBindings_, false ); + } + else + { + stmt_.addBinding( columnBindings_, false ); + stmt_.fixupBinding(); + } + // execute the statement and reset bindings + stmt_.execute(); + if( ! stmt_.done() ) + { + throw std::runtime_error( "SqlInserter::execute(): " + "statement not done after calling execute" ); + } + executed_ = true; + resetBindings(); + } + + std::string getSql() + { + if( sql_.empty() ) + { + makeSql(); + } + std::string sqlcopy = sql_; + sql_.clear(); + return sqlcopy; + } + + std::size_t getBindingCount() const + { + return columnBindings_.size(); + } + + bool isExecuted() const + { + return executed_; + } + +private: + /// Vector type to hold info value bindings + typedef Poco::Data::AbstractBindingVec BindingVec; + + /// Reference to the database session + Poco::Data::Session* session_; + /// Reusable statement object, reset after every execution + LogStatement stmt_; + /// Stores the SQL insert command for fast inserter reuse + std::string sql_; + /// Stores the table name where data is inserted + std::string tableName_; + /// Stores the column names for which data is provided + std::string columnNames_; + /// Stores the same amount of place holders as column names + std::string placeholders_; + /// Stores value bindings to column data to be inserted + BindingVec columnBindings_; + /// Stores whether the statement has been executed with the current bindings + bool executed_; + /// Stores whether the statement shall be executed automatically during destruction + bool autoExec_; + +private: + + /// Create an SQL string from the accumulated column data (names, placeholders) + void makeSql() + { + sql_.append( "INSERT INTO " ); + sql_.append( tableName_ ); + sql_.append( "(" ); + sql_.append( columnNames_ ); + sql_.append( ") VALUES(" ); + sql_.append( placeholders_ ); + sql_.append( ")" ); + } + + /// Clear the binding vector (after executing the SQL insert) + void resetBindings() + { + columnBindings_.clear(); + stmt_.bindings().clear(); + } + +private: + /// Loop type to iterate over an info list, adding column definitions to a string + template < typename InfoListT, int Index > + struct ColumnLoop + { + static void call( std::string& columnNames, std::string& placeholders ) + { + // recurse first + ColumnLoop< InfoListT, Index - 1 >::call( columnNames, placeholders ); + + // add column data + typedef typename TypeOf< InfoListT, Index >::type CurrentType; + columnNames.append( 1, ',' ); + columnNames.append( CurrentType::getName().c_str() ); + placeholders.append( ",?" ); + } + }; + +#ifndef DOXYGEN_SKIP + /// Partial specialization of ColumnLoop, stops the info list recursion +#endif + template < typename InfoListT > + struct ColumnLoop< InfoListT, 0 > + { + static void call( std::string& columnNames, std::string& placeholders ) + { + // end recursion, add first column data + typedef typename TypeOf< InfoListT, 0 >::type CurrentType; + if( ! columnNames.empty() ) + { + columnNames.append( 1, ',' ); + placeholders.append( 1, ',' ); + } + columnNames.append( CurrentType::getName().c_str() ); + placeholders.append( 1, '?' ); + } + }; + + /// Functor for adding record info value bindings + struct ValueAdder + { + BindingVec& bindings_; + + ValueAdder( BindingVec& bindings ) + : bindings_( bindings ) + {} + + // overload for StringLiteral value + void operator()( StringLiteral const& name, StringLiteral const& val, bool found ) + { + if( found ) + { + // must use string wrapper here because ODBC bind is not implemented for const char* + bindings_.push_back( Poco::Data::Keywords::bind( std::string( val.c_str() ) ) ); + } + else + { + bindings_.push_back( Poco::Data::Keywords::useRef( Poco::Data::Keywords::null ) ); + } + } + + template < typename InfoValueT > + void operator()( StringLiteral const& name, InfoValueT const& val, bool found ) + { + if( found ) + { + bindings_.push_back( Poco::Data::Keywords::useRef( val ) ); + } + else + { + bindings_.push_back( Poco::Data::Keywords::useRef( Poco::Data::Keywords::null ) ); + } + } + }; + + /// Functor for adding record info names, placeholders, and values + struct NameValueAdder + { + std::string& names_; + std::string& placeholders_; + BindingVec& bindings_; + + NameValueAdder( std::string& names, std::string& placeholders, BindingVec& bindings ) + : names_( names ) + , placeholders_( placeholders ) + , bindings_( bindings ) + {} + + // overload for StringLiteral value + void operator()( StringLiteral const& name, StringLiteral const& val, bool found ) + { + if( ! names_.empty() ) + { + names_.append( 1, ',' ); + placeholders_.append( 1, ',' ); + } + names_.append( name.c_str() ); + placeholders_.append( 1, '?' ); + if( found ) + { + bindings_.push_back( Poco::Data::Keywords::bind( std::string( val.c_str() ) ) ); + } + else + { + bindings_.push_back( Poco::Data::Keywords::useRef( Poco::Data::Keywords::null ) ); + } + } + + template < typename InfoValueT > + void operator()( StringLiteral const& name, InfoValueT const& val, bool found ) + { + if( ! names_.empty() ) + { + names_.append( 1, ',' ); + placeholders_.append( 1, ',' ); + } + names_.append( name.c_str() ); + placeholders_.append( 1, '?' ); + if( found ) + { + bindings_.push_back( Poco::Data::Keywords::useRef( val ) ); + } + else + { + bindings_.push_back( Poco::Data::Keywords::useRef( Poco::Data::Keywords::null ) ); + } + } + }; +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_SQLINSERTER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/SqlTableCreator.h b/odemx-lite/external/CppLog/include/CppLog/detail/SqlTableCreator.h new file mode 100644 index 0000000000000000000000000000000000000000..817890913e7c01021c2a5257cb1d70207a497ce8 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/SqlTableCreator.h @@ -0,0 +1,208 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file SqlTableCreator.h + * @author Ronald Kluth + * @date created at 2009/07/30 + * @brief Declaration and implementation of class SqlTableCreator + * @since 0.1 + */ + +#ifndef LOG_DETAIL_SQLTABLECREATOR_INCLUDED +#define LOG_DETAIL_SQLTABLECREATOR_INCLUDED + +#include <Poco/Data/Session.h> +#include <Poco/Data/Statement.h> + +#include <string> +#ifdef _MSC_VER +#include <array> +#else +#include <array> +#endif + +#include <vector> + +namespace Log { +namespace Detail { + +/** + * @brief Helper class to build SQL CREATE TABLE statements + */ +class SqlTableCreator +{ +public: + /// Construction + SqlTableCreator( std::string const& tableName, Poco::Data::Session& session ) + : session_( session ) + , tableName_( tableName ) + , executed_( false ) + {} + + /// Destruction, executes the statement if necessary + ~SqlTableCreator() + { + if( ! executed_ ) + { + execute(); + } + } + + /// Add a table column to the statement with its corresponding SQL data type + SqlTableCreator& column( std::string const& columnName, std::string const& sqlDataType ) + { + if( ! isValidColumnName( columnName ) ) + { + // prevent automatic execution in destructor and throw error + executed_ = true; + throw std::runtime_error( std::string( "SqlTableCreator::column():" + "invalid column name: " ) + columnName ); + } + + if( ! columnDefs_.empty() ) + { + columnDefs_.append( 1, ',' ); + } + columnDefs_.append( columnName + " " + sqlDataType ); + return *this; + } + + /// Add table columns according to the given info type list and corresponding SQL types + template < typename InfoListT > + SqlTableCreator& columns( + std::array< std::string, SizeOf< InfoListT >::value > const& sqlDataTypes ) + { + if( SizeOf< InfoListT >::value > 0 ) + { + try + { + ColumnLoop< + InfoListT, + SizeOf< InfoListT >::value - 1 + >::call( columnDefs_, sqlDataTypes ); + } + catch( std::runtime_error const& ) + { + executed_ = true; + throw; + } + } + return *this; + } + + /// Add a table contraint specifying the primary key + SqlTableCreator& primaryKey( std::string const& columnName ) + { + tableConstraints_.append( ",PRIMARY KEY(" ); + tableConstraints_.append( columnName ); + tableConstraints_.append( ")" ); + return *this; + } + + /// Execute the consructed statement, which creates the table in the database + void execute() + { + if( ! executed_ ) + { + // create the statement and add text + session_.begin(); + + Poco::Data::Statement stmt( session_ ); + stmt << "CREATE TABLE " << tableName_ << " (" + << columnDefs_ + << tableConstraints_ + << ")"; + + stmt.execute(); + + session_.commit(); + executed_ = true; + } + } + +private: + /// Reference to the database session + Poco::Data::Session& session_; + /// Stores the table name where data is inserted + std::string tableName_; + /// Stores the column names and sql data types + std::string columnDefs_; + /// Stores the table constraints + std::string tableConstraints_; + /// Stores whether the statement has been executed yet + bool executed_; + +private: + + /// Check if a column name contains spaces, which would create invalid SQL + static bool isValidColumnName( std::string const& columnName ) + { + std::size_t found = columnName.find_first_of( " " ); + return found == std::string::npos; + } + + /// Loop type to iterate over an info list, adding column definitions to a string + template < typename InfoListT, int Index > + struct ColumnLoop + { + static void call( std::string& columnDefs, + std::array< std::string, SizeOf< InfoListT >::value > const& sqlDataTypes ) + { + // recurse first + ColumnLoop< InfoListT, Index - 1 >::call( columnDefs, sqlDataTypes ); + + // check and add column data + typedef typename TypeOf< InfoListT, Index >::type CurrentType; + std::string columnName = CurrentType::getName().c_str(); + if( ! isValidColumnName( columnName ) ) + { + // prevent automatic execution in destructor and throw error + throw std::runtime_error( std::string( "SqlTableCreator::ColumnLoop::call():" + "invalid column name: " ) + columnName ); + } + columnDefs.append( "," ); + columnDefs.append( columnName ); + columnDefs.append( " " ); + columnDefs.append( sqlDataTypes[ Index ] ); + } + }; + +#ifndef DOXYGEN_SKIP + /// Partial specialization of ColumnLoop, stops the info list recursion +#endif + template < typename InfoListT > + struct ColumnLoop< InfoListT, 0 > + { + static void call( std::string& columnDefs, + std::array< std::string, SizeOf< InfoListT >::value > const& sqlDataTypes ) + { + // end recursion, add first column data + // check and add column data + typedef typename TypeOf< InfoListT, 0 >::type CurrentType; + std::string columnName = CurrentType::getName().c_str(); + if( ! isValidColumnName( columnName ) ) + { + // prevent automatic execution in destructor and throw error + throw std::runtime_error( std::string( "SqlTableCreator::ColumnLoop::call():" + "invalid column name: " ) + columnName ); + } + + if( ! columnDefs.empty() ) + { + columnDefs.append( "," ); + } + columnDefs.append( columnName ); + columnDefs.append( " " ); + columnDefs.append( sqlDataTypes[ 0 ] ); + } + }; +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_SQLTABLECREATOR_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/Strip.h b/odemx-lite/external/CppLog/include/CppLog/detail/Strip.h new file mode 100644 index 0000000000000000000000000000000000000000..58bcd90cfddc514d01f29e5e581aaa3605d99426 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/Strip.h @@ -0,0 +1,63 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Strip.h + * @author Ronald Kluth + * @date created at 2009/09/06 + * @brief Declaration and implementation of class template Strip + * @since 0.1 + */ + +#ifndef LOG_DETAIL_STRIP_INCLUDED +#define LOG_DETAIL_STRIP_INCLUDED + +namespace Log { +namespace Detail { + +/** + * @brief Strips pointer or reference types to enable use of the real type + * + * This is a helper class for templates that need to acquire the basic type + * of a parameter type, even if a pointer or reference was given. Used to + * implement a specialization of InfoType so it can hold pointer types. + * + * @see InfoType + */ +template < typename T > +struct Strip +{ + typedef T Type; + typedef T* Ptr; + typedef T& Ref; +}; + +#ifndef DOXYGEN_SKIP +/// Specialization for pointer types +#endif +template < typename T > +struct Strip< T* > +{ + typedef T Type; + typedef T* Ptr; + typedef T& Ref; +}; + +#ifndef DOXYGEN_SKIP +/// Specialization for reference types +#endif +template < typename T > +struct Strip< T& > +{ + typedef T Type; + typedef T* Ptr; + typedef T& Ref; +}; + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_STRIP_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/TypeInfo.h b/odemx-lite/external/CppLog/include/CppLog/detail/TypeInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..6be631ed1dafef959b0b11d207f78424836d2744 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/TypeInfo.h @@ -0,0 +1,173 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +/** + * @file detail/TypeInfo.h + * @brief Adapted Loki::TypeInfo from Andrei Alexandrescu's Modern C++ Design + * @since 0.1 + */ + +#ifndef LOG_DETAIL_TYPEINFO_INCLUDED +#define LOG_DETAIL_TYPEINFO_INCLUDED + +#include "TypeToString.h" + +#include <cassert> +#include <string> +#include <typeinfo> +#ifdef _MSC_VER +#include <functional> +#else +#include <functional> +#endif + +namespace Log { +namespace Detail { + +/** + * @brief This class offers a first-class, comparable wrapper over std::type_info + * + * Sometimes it is useful to be able to store type infomation objects in standard + * containers, which is not possible with @c std::type_info. The logging library + * uses it as key type in an std::map to look up info type values transported in + * record objects. + * + * @note This is a modified version of Andrei Alexandrescu's Loki::TypeInfo. + */ +class TypeInfo +{ +public: + /// Required for default construction and initialization check + class Null {}; + + /// Default-Construction (needed for containers) + TypeInfo(); + /// Construction (also conversion operator) + TypeInfo( const std::type_info& ); + + /// Access for the wrapped std::type_info + const std::type_info& get() const; + /// Check if the type info is not TypeInfo::Null + bool isSet() const; + /// Get a (demangled) string representation of the type name + const std::string toString() const; + + /// Compatibility function + bool before( const TypeInfo& rhs ) const; + /// Compatibility function + const char* name() const; + +private: + /// Pointer to the actual std::type_info object + const std::type_info* pInfo_; +}; + +//------------------------------------------------------construction/destruction + +inline TypeInfo::TypeInfo() +{ + pInfo_ = &typeid( TypeInfo::Null ); + assert( pInfo_ ); +} + +inline TypeInfo::TypeInfo( const std::type_info& type ) +: pInfo_( &type ) +{ + assert( pInfo_ ); +} + +//----------------------------------------------------------comparison operators + +inline bool operator==( const TypeInfo& lhs, const TypeInfo& rhs ) +{ + return ( lhs.get() == rhs.get() ) != 0; +} + +inline bool operator<( const TypeInfo& lhs, const TypeInfo& rhs ) +{ + return lhs.before( rhs ); +} + +inline bool operator!=( const TypeInfo& lhs, const TypeInfo& rhs ) +{ + return ! ( lhs == rhs ); +} + +inline bool operator>( const TypeInfo& lhs, const TypeInfo& rhs ) +{ + return rhs < lhs; +} + +inline bool operator<=( const TypeInfo& lhs, const TypeInfo& rhs ) +{ + return ! ( lhs > rhs ); +} + +inline bool operator>=( const TypeInfo& lhs, const TypeInfo& rhs ) +{ + return ! ( lhs < rhs ); +} + +//----------------------------------------------------------------access methods + +inline bool TypeInfo::isSet() const +{ + return ( *this != typeid(TypeInfo::Null) ); +} + +inline const std::type_info& TypeInfo::get() const +{ + assert( pInfo_ ); + return *pInfo_; +} + +inline const std::string TypeInfo::toString() const +{ + assert( pInfo_ ); + return typeToString( *pInfo_ ); +} + +//---------------------------------------------------------compatibility methods + +inline bool TypeInfo::before( const TypeInfo& rhs ) const +{ + assert( pInfo_ ); + // type_info::before return type is int in some VC libraries + return pInfo_->before( *rhs.pInfo_ ) != 0; +} + +inline const char* TypeInfo::name() const +{ + assert( pInfo_ ); + return pInfo_->name(); +} + +} } // namespace Log::Detail + +namespace std { + +template <> +struct hash< Log::Detail::TypeInfo > +{ + std::size_t operator ()( const Log::Detail::TypeInfo& val ) const + { // return hash value for val + hash< const std::type_info* > make_hash; + return make_hash( &val.get() ); + } +}; + +} // namespace std + +#endif /* LOG_DETAIL_TYPEINFO_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/TypeToString.h b/odemx-lite/external/CppLog/include/CppLog/detail/TypeToString.h new file mode 100644 index 0000000000000000000000000000000000000000..8640e770007394d4bc3213bace1acb152e7683f0 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/TypeToString.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file detail/TypeToString.h + * @author Ronald Kluth + * @date created at 2009/03/29 + * @brief Declaration and implementation of the free function typeToString() + * @since 0.1 + */ + +#ifndef LOG_DETAIL_TYPETOSTRING_INCLUDED +#define LOG_DETAIL_TYPETOSTRING_INCLUDED + +// typeid().name() returns a mangled type name on GCC, +// needs to be treated differently than other compilers, +// the following includes the demangling library header + +#if defined(__GNUC__) /* GNU Compiler */ + + #include <cxxabi.h> + +#endif + +#include <cstdlib> +#include <sstream> +#include <stdexcept> +#include <string> +#include <typeinfo> + +namespace Log { +namespace Detail { + +/** + * @brief Get a string representation of the type name + * @param type reference to a type_info object returned by typeid() + * @return the type name as string + * + * The method @c std::type_info::name returns a mangled type name on GCC + * and thus needs to be treated differently than on other compilers. + * This function applies demangling to retrieve a human-readable + * string representation of type names. + */ +inline std::string typeToString( const std::type_info& type ) +{ +#if defined(__GNUC__) /* GNU Compiler */ + + int demangleStatus = -1; + + char* cString = abi::__cxa_demangle( type.name(), 0, 0, &demangleStatus ); + +// demangleStatus is set to one of the following values: +// 0: The demangling operation succeeded. +// -1: A memory allocation failure occurred. +// -2: mangled_name is not a valid name under the C++ ABI mangling rules. +// -3: One of the arguments is invalid. + + if( demangleStatus != 0 ) + { + std::ostringstream stream; + stream << "typeToString() failed," + << " error code: " << demangleStatus + << " while trying to convert '" << type.name() << "'" + << std::endl; + + throw std::runtime_error( stream.str() ); + } + + std::string typeString; + if( cString != NULL ) + { + typeString = cString; + std::free( cString ); + } + +#else // other compilers should give a demangled name + + std::string typeString( type.name() ); + +#endif + + return typeString; +} + +} } // namespace Log::Detail + +#endif /* LOG_DETAIL_TYPETOSTRING_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/detail/string_literal.hpp b/odemx-lite/external/CppLog/include/CppLog/detail/string_literal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7c9ab3e74b5379dcb785b77375fd5c0e167f870a --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/detail/string_literal.hpp @@ -0,0 +1,523 @@ +/* + * (C) 2007 Andrey Semashev + * + * Use, modification and distribution is subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/libs/log/doc/log.html. + */ +/*! + * \file string_literal.hpp + * \author Andrey Semashev + * \date 24.06.2007 + * + * The header contains implementation of a constant string literal wrapper. + */ + +#if defined(_MSC_VER) && _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_ + +#include <stdexcept> +#include <iosfwd> +#include <string> +#include <iterator> +#include <algorithm> +#include <functional> +#include <ios> +//#include <boost/operators.hpp> +//#include <boost/throw_exception.hpp> +//#include <boost/compatibility/cpp_c_headers/cstddef> +//#include <boost/type_traits/is_same.hpp> +//#include <boost/utility/enable_if.hpp> +//#include <boost/log/detail/prologue.hpp> + +namespace boost { + +namespace log { + +/*! + * \brief String literal wrapper + * + * The \c basic_string_literal is a thin wrapper around a constant string literal. + * It provides interface similar to STL strings, but because of read-only nature + * of string literals, lacks ability to modify string contents. However, + * \c basic_string_literal objects can be assigned to and cleared. + * + * The main advantage of this class comparing to other string classes is that + * it doesn't dynamically allocate memory and therefore is fast, thin and exception safe. + */ +template< typename CharT, typename TraitsT = std::char_traits< CharT > > +class basic_string_literal +{ + //! Self type + typedef basic_string_literal< CharT, TraitsT > this_type; + +public: + typedef CharT value_type; + typedef TraitsT traits_type; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* const_pointer; + typedef value_type const& const_reference; + typedef const value_type* const_iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + + //! Corresponding STL string type + typedef std::basic_string< value_type, traits_type > string_type; + +private: + //! Pointer to the beginning of the literal + const_pointer m_pStart; + //! Length + size_type m_Len; + + //! Empty string literal to support clear + static const value_type g_EmptyString[1]; + +public: + /*! + * Constructor + * + * \post <tt>empty() == true</tt> + */ + basic_string_literal() { clear(); } + + /*! + * Constructor from a string literal + * + * \post <tt>*this == p</tt> + * \param p A zero-terminated constant sequence of characters + */ + template< typename T, size_type LenV > + basic_string_literal( T(&p)[LenV] ) + : m_pStart(p), m_Len(LenV - 1) + { + } + + /*! + * Copy constructor + * + * \post <tt>*this == that</tt> + * \param that Source literal to copy string from + */ + basic_string_literal(basic_string_literal const& that) + : m_pStart(that.m_pStart), m_Len(that.m_Len) + { + } + + /*! + * Assignment operator + * + * \post <tt>*this == that</tt> + * \param that Source literal to copy string from + */ + this_type& operator= (this_type const& that) + { + return assign(that); + } + /*! + * Assignment from a string literal + * + * \post <tt>*this == p</tt> + * \param p A zero-terminated constant sequence of characters + */ + template< typename T, size_type LenV > + this_type& + operator= ( T(&p)[LenV] ) + { + return assign(p); + } + + /*! + * Lexicographical comparison (equality) + * + * \param that Comparand + * \return \c true if the comparand string equals to this string, \c false otherwise + */ + bool operator== (this_type const& that) const + { + return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) == 0); + } + /*! + * Lexicographical comparison (equality) + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return \c true if the comparand string equals to this string, \c false otherwise + */ + bool operator== (const_pointer str) const + { + return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) == 0); + } + /*! + * Lexicographical comparison (equality) + * + * \param that Comparand + * \return \c true if the comparand string equals to this string, \c false otherwise + */ + bool operator== (string_type const& that) const + { + return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) == 0); + } + + /*! + * Lexicographical comparison (less ordering) + * + * \param that Comparand + * \return \c true if this string is less than the comparand, \c false otherwise + */ + bool operator< (this_type const& that) const + { + return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) < 0); + } + /*! + * Lexicographical comparison (less ordering) + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return \c true if this string is less than the comparand, \c false otherwise + */ + bool operator< (const_pointer str) const + { + return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) < 0); + } + /*! + * Lexicographical comparison (less ordering) + * + * \param that Comparand + * \return \c true if this string is less than the comparand, \c false otherwise + */ + bool operator< (string_type const& that) const + { + return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) < 0); + } + + /*! + * Lexicographical comparison (greater ordering) + * + * \param that Comparand + * \return \c true if this string is greater than the comparand, \c false otherwise + */ + bool operator> (this_type const& that) const + { + return (compare_internal(m_pStart, m_Len, that.m_pStart, that.m_Len) > 0); + } + /*! + * Lexicographical comparison (greater ordering) + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return \c true if this string is greater than the comparand, \c false otherwise + */ + bool operator> (const_pointer str) const + { + return (compare_internal(m_pStart, m_Len, str, traits_type::length(str)) > 0); + } + /*! + * Lexicographical comparison (greater ordering) + * + * \param that Comparand + * \return \c true if this string is greater than the comparand, \c false otherwise + */ + bool operator> (string_type const& that) const + { + return (compare_internal(m_pStart, m_Len, that.c_str(), that.size()) > 0); + } + + /*! + * Subscript operator + * + * \pre <tt>i < size()</tt> + * \param i Requested character index + * \return Constant reference to the requested character + */ + const_reference operator[] (size_type i) const + { + return m_pStart[i]; + } + /*! + * Checked subscript + * + * \param i Requested character index + * \return Constant reference to the requested character + * \throw An <tt>std::exception</tt>-based exception if index \a i is out of string boundaries + */ + const_reference at(size_type i) const + { + if (i < m_Len) + return m_pStart[i]; + else + throw std::out_of_range("basic_string_literal::at: the index value is out of range"); + } + + /*! + * \return Pointer to the beginning of the literal + */ + const_pointer c_str() const { return m_pStart; } + /*! + * \return Pointer to the beginning of the literal + */ + const_pointer data() const { return m_pStart; } + /*! + * \return Length of the literal + */ + size_type size() const { return m_Len; } + /*! + * \return Length of the literal + */ + size_type length() const { return m_Len; } + + /*! + * \return \c true if the literal is an empty string, \c false otherwise + */ + bool empty() const + { + return (m_Len == 0); + } + + /*! + * \return Iterator that points to the first character of the literal + */ + const_iterator begin() const { return m_pStart; } + /*! + * \return Iterator that points after the last character of the literal + */ + const_iterator end() const { return m_pStart + m_Len; } + /*! + * \return Reverse iterator that points to the last character of the literal + */ + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + /*! + * \return Reverse iterator that points before the first character of the literal + */ + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + + /*! + * \return STL string constructed from the literal + */ + string_type str() const + { + return string_type(m_pStart, m_Len); + } + + /*! + * The method clears the literal + * + * \post <tt>empty() == true</tt> + */ + void clear() + { + m_pStart = g_EmptyString; + m_Len = 0; + } + /*! + * The method swaps two literals + */ + void swap(this_type& that) + { + std::swap(m_pStart, that.m_pStart); + std::swap(m_Len, that.m_Len); + } + + /*! + * Assignment from another literal + * + * \post <tt>*this == that</tt> + * \param that Source literal to copy string from + */ + this_type& assign(this_type const& that) + { + m_pStart = that.m_pStart; + m_Len = that.m_Len; + return *this; + } + /*! + * Assignment from another literal + * + * \post <tt>*this == p</tt> + * \param p A zero-terminated constant sequence of characters + */ + template< typename T, size_type LenV > + this_type& + assign( T(&p)[LenV] ) + { + m_pStart = p; + m_Len = LenV - 1; + return *this; + } + + /*! + * The method copies the literal or its portion to an external buffer + * + * \pre <tt>pos < size()</tt> + * \param str Pointer to the external buffer beginning. Must not be NULL. + * The buffer must have enough capacity to accommodate the requested number of characters. + * \param n Maximum number of characters to copy + * \param pos Starting position to start copying from + * \return Number of characters copied + * \throw An <tt>std::exception</tt>-based exception if \a pos is out of range. + */ + size_type copy(value_type* str, size_type n, size_type pos = 0) const + { + if (pos <= size()) + { + const size_type len = (std::min)(n, size() - pos); + traits_type::copy(str, m_pStart + pos, len); + return len; + } + else + throw std::out_of_range("basic_string_literal::copy: the position is out of range"); + } + + /*! + * Lexicographically compares the argument string to a part of this string + * + * \pre <tt>pos < size()</tt> + * \param pos Starting position within this string to perform comparison to + * \param n Length of the substring of this string to perform comparison to + * \param str Comparand. Must point to a sequence of characters, must not be NULL. + * \param len Number of characters in the sequence \a str. + * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, + * a positive value if this string is greater than the comparand. + * \throw An <tt>std::exception</tt>-based exception if \a pos is out of range. + */ + int compare(size_type pos, size_type n, const_pointer str, size_type len) const + { + if (pos <= size()) + { + const size_type compare_size = (std::min)((std::min)(n, len), size() - pos); + return compare_internal(m_pStart + pos, compare_size, str, compare_size); + } + else + throw std::out_of_range("basic_string_literal::compare: the position is out of range"); + } + /*! + * Lexicographically compares the argument string to a part of this string + * + * \pre <tt>pos < size()</tt> + * \param pos Starting position within this string to perform comparison to + * \param n Length of the substring of this string to perform comparison to + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, + * a positive value if this string is greater than the comparand. + * \throw An <tt>std::exception</tt>-based exception if \a pos is out of range. + */ + int compare(size_type pos, size_type n, const_pointer str) const + { + return compare(pos, n, str, traits_type::length(str)); + } + /*! + * Lexicographically compares the argument string literal to a part of this string + * + * \pre <tt>pos < size()</tt> + * \param pos Starting position within this string to perform comparison to + * \param n Length of the substring of this string to perform comparison to + * \param that Comparand + * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, + * a positive value if this string is greater than the comparand. + * \throw An <tt>std::exception</tt>-based exception if \a pos is out of range. + */ + int compare(size_type pos, size_type n, this_type const& that) const + { + return compare(pos, n, that.c_str(), that.size()); + } + /*! + * Lexicographically compares the argument string to this string + * + * \param str Comparand. Must point to a sequence of characters, must not be NULL. + * \param len Number of characters in the sequence \a str. + * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, + * a positive value if this string is greater than the comparand. + */ + int compare(const_pointer str, size_type len) const + { + return compare(0, m_Len, str, len); + } + /*! + * Lexicographically compares the argument string to this string + * + * \param str Comparand. Must point to a zero-terminated sequence of characters, must not be NULL. + * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, + * a positive value if this string is greater than the comparand. + */ + int compare(const_pointer str) const + { + return compare(0, m_Len, str, traits_type::length(str)); + } + /*! + * Lexicographically compares the argument string to this string + * + * \param that Comparand + * \return Zero if the comparand equals this string, a negative value if this string is less than the comparand, + * a positive value if this string is greater than the comparand. + */ + int compare(this_type const& that) const + { + return compare(0, m_Len, that.c_str(), that.size()); + } + +private: + + //! Internal comparison implementation + static int compare_internal(const_pointer pLeft, size_type LeftLen, const_pointer pRight, size_type RightLen) + { + if (pLeft != pRight) + { + const int result = traits_type::compare(pLeft, pRight, (std::min)(LeftLen, RightLen)); + if (result != 0) + return result; + } + return (LeftLen - RightLen); + } +}; + +template< typename CharT, typename TraitsT > +typename basic_string_literal< CharT, TraitsT >::value_type const +basic_string_literal< CharT, TraitsT >::g_EmptyString[1] = +{ + typename basic_string_literal< CharT, TraitsT >::value_type() +}; + +//! Output operator +template< typename CharT, typename StrmTraitsT, typename LitTraitsT > +inline std::basic_ostream< CharT, StrmTraitsT >& operator<< ( + std::basic_ostream< CharT, StrmTraitsT >& strm, basic_string_literal< CharT, LitTraitsT > const& lit) +{ + strm.write(lit.c_str(), static_cast< std::streamsize >(lit.size())); + return strm; +} + +//! External swap +template< typename CharT, typename TraitsT > +inline void swap( + basic_string_literal< CharT, TraitsT >& left, + basic_string_literal< CharT, TraitsT >& right) +{ + left.swap(right); +} + +typedef basic_string_literal< char > string_literal; //!< String literal type for narrow characters +typedef basic_string_literal< wchar_t > wstring_literal; //!< String literal type for wide characters + +//! Creates a string literal wrapper from a constant string literal +template< typename T, std::size_t LenV > +inline string_literal make_string_literal( T(&p)[LenV] ) +{ + return string_literal(p); +} + +//! Creates a string literal wrapper from a constant string literal +template< typename T, std::size_t LenV > +inline wstring_literal make_wstring_literal( T(&p)[LenV] ) +{ + return wstring_literal(p); +} + +} // namespace log + +} // namespace boost + +#endif // BOOST_LOG_UTILITY_STRING_LITERAL_HPP_INCLUDED_ diff --git a/odemx-lite/external/CppLog/include/CppLog/output/DatabaseAccessor.h b/odemx-lite/external/CppLog/include/CppLog/output/DatabaseAccessor.h new file mode 100644 index 0000000000000000000000000000000000000000..6e2c38e268777318fb3a651f23736f3aa6e3d4ed --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/output/DatabaseAccessor.h @@ -0,0 +1,267 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file DatabaseAccessor.h + * @author Ronald Kluth + * @date 2009/06/17 + * @brief Declaration and implementation of class DatabaseAccessor + * @since 0.1 + */ + +#ifndef LOG_OUTPUT_DATABASEACCESSOR_INCLUDED +#define LOG_OUTPUT_DATABASEACCESSOR_INCLUDED + +#ifdef CPPLOG_USE_DATABASE + +#include "../../setup.h" +#include "../Consumer.h" +#include "../StringLiteral.h" +#include "../detail/SqlTableCreator.h" +#include "../detail/SqlInserter.h" + +#include <Poco/Data/Session.h> +#include <Poco/Runnable.h> +#include <Poco/Thread.h> +#include <Poco/ThreadLocal.h> +#include <Poco/Types.h> + +#if defined CPPLOG_USE_ODBC && defined CPPLOG_USE_SQLITE +#error "CPPLOG_USE_ODBC and CPPLOG_USE_SQLITE are defined: ambiguous setup" +#endif + +#if defined CPPLOG_USE_ODBC + #include <Poco/Data/ODBC/Connector.h> + #include <Poco/Data/ODBC/SessionImpl.h> +#elif defined CPPLOG_USE_SQLITE + #include <Poco/Data/SQLite/Connector.h> +#else +#error "Neither CPPLOG_USE_ODBC nor CPPLOG_USE_SQLITE are defined: cannot register connector" +#endif + +#include <algorithm> // for_each +#include <cstddef> // size_t +#include <memory> // auto_ptr +#include <vector> + +namespace Log { + +/** + * @brief Base class that gives log consumers database access + * + * Even basic database interaction requires different SQL syntax on different + * database management systems. This class provides an abstraction layer for + * common database operations so that log consumers can use a single interface + * regardless of the underlying database, as long as it is supported by this + * class. + * + * @note This class requires the Data module of the Poco C++ libraries. + */ +class DatabaseAccessor +{ +public: + /// Pull SqlTableCreator into this scope + typedef Detail::SqlTableCreator SqlTableCreator; + /// Pulls SqlInserter into this scope, improves usability + typedef Detail::SqlInserter SqlInserter; + + /// Construction + DatabaseAccessor( const std::string& connectionString ) + : session_( 0 ) + { +#if defined CPPLOG_USE_ODBC + Poco::Data::ODBC::Connector::registerConnector(); + session_.reset( new Poco::Data::Session( "ODBC", connectionString ) ); + Poco::Data::ODBC::SessionImpl* impl = static_cast< Poco::Data::ODBC::SessionImpl* >( session_->impl() ); + if( impl->isAutoCommit() ) + { + impl->autoCommit( "", false ); + } +#elif defined CPPLOG_USE_SQLITE + Poco::Data::SQLite::Connector::registerConnector(); + session_.reset( new Poco::Data::Session( "SQLite", connectionString ) ); +#endif + } + + /// Destruction + ~DatabaseAccessor() + { + } + + /// Create a table by appending columns to a table builder object + SqlTableCreator createTable( const std::string& tableName ) + { + return SqlTableCreator( tableName, *session_ ); + } + + /// Create an SQL inserter for reuse of a prepared statement + std::auto_ptr< SqlInserter > createInserter() + { + return std::auto_ptr< SqlInserter >( new SqlInserter( *session_, false ) ); + } + + /// Insert data into a table by appending values to an insert builder object + SqlInserter insertIntoTable( const std::string& tableName ) + { + return SqlInserter( tableName, *session_, true ); + } + + /// Check if a table with the given name already exists + bool tableExists( const std::string& tableName ) + { + using namespace Poco::Data; + using namespace Poco::Data::Keywords; + int count = 0; + Statement stmt( *session_ ); + try + { +#if defined CPPLOG_USE_ODBC + stmt << "SELECT count(table_name) FROM information_schema.tables " + "WHERE table_name = ?;", bind( tableName ), into( count ); +#elif defined CPPLOG_USE_SQLITE + stmt << "Select count(*) from sqlite_master where name=?;" + ,useRef( tableName ), into( count ); +#else +#error "DatabaseAccessor::tableExists() requires ODBC or SQLITE to be enabled" +#endif + stmt.execute(); + } + catch( const DataException& ) + { + throw; + } + return count > 0; + } + + /// Get maximum value of @c column in @c table and store it in @c valueHolder + template < typename T > + void getMaxColumnValue( std::string const& table, std::string const& column, + T& valueHolder ) + { + using namespace Poco::Data; + using namespace Poco::Data::Keywords; + try + { + *session_ << "SELECT MAX(" << column << ") FROM " << table + ,into( valueHolder ), now; + } + catch( const DataException& ) + { + throw; + } + } + + /// Count the number of rows in the given table + Poco::UInt64 getRowCount( std::string const& table ) + { + using namespace Poco::Data; + using namespace Poco::Data::Keywords; + try + { + Poco::UInt64 rowCount = 0; + *session_ << "SELECT COUNT(*) FROM " << table + ,into( rowCount ), now; + return rowCount; + } + catch( const DataException& ) + { + throw; + } + } + + /// Get the current time from the database + std::string getCurrentDatabaseTime() + { + using namespace Poco::Data; + using namespace Poco::Data::Keywords; + std::string currentTime; + Statement stmt( *session_ ); + try + { +#if defined CPPLOG_USE_ODBC + stmt << "SELECT CURRENT_TIMESTAMP;", into( currentTime ); +#elif defined CPPLOG_USE_SQLITE + stmt << "SELECT DATETIME('now');", into( currentTime ); +#else +#error "DatabaseAccessor::getCurrentDatabaseTime() requires ODBC or SQLITE to be enabled" +#endif + stmt.execute(); + } + catch( const DataException& ) + { + throw; + } + return currentTime; + } + + /** + * @brief Writes buffered records to the database + * @tparam RecordBufferT Buffer type, must support forward iteration + * @tparam InsertFuncT Function type to call with RecordBufferT::value_type + * + * @param buffer Record buffer to write the database, is cleared afterwards + * @param insertFunc Function called for each record to write to the database + * + * This method is implmented in terms of std::for_each, meaning the buffer + * must provide the methods @c begin and @c end, which return iterators to + * the start and jsut past the end of the given buffer. The insert function + * or functor must also provide the correct signature, which only takes + * one buffered record as parameter. + */ + template < typename RecordBufferT, typename InsertFuncT > + void storeData( RecordBufferT& buffer, const InsertFuncT& insertFunc ) + { + using namespace Poco::Data; + using namespace Poco::Data::Keywords; + + // BEGIN TRANSACTION + session_->begin(); + + std::for_each( buffer.begin(), buffer.end(), insertFunc ); + + // COMMIT + session_->commit(); + } + +#if defined CPPLOG_USE_SQLITE || defined CPPLOG_USE_POSTGRESQL + + /// Get the last automatically generated serial/identity value + Poco::UInt64 getLastInsertId( const std::string& seqName = "" ) + { + using namespace Poco::Data; + using namespace Poco::Data::Keywords; + try + { + Poco::UInt64 lastId; + +#if defined CPPLOG_USE_POSTGRESQL + *session_ << "SELECT currval('" << seqName << "')", into( lastId ), now; +#elif defined CPPLOG_USE_SQLITE + *session_ << "SELECT last_insert_rowid();", into( lastId ), now; +#else +#error "DatabaseAccessor::getLastInsertId() requires SQLITE or POSTGRESQL to be enabled" +#endif + + return lastId; + } + catch( const DataException& ) + { + throw; + } + } +#endif + +private: + /// Pointer to the database session the log information is written to + std::auto_ptr< Poco::Data::Session > session_; +}; + +} // namespace Log + +#endif /* CPPLOG_USE_DATABASE */ + +#endif /* LOG_OUTPUT_DATABASEACCESSOR_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/output/OStreamWriter.h b/odemx-lite/external/CppLog/include/CppLog/output/OStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..99233787ba2954252256f55a7c25e4bdd8f6884a --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/output/OStreamWriter.h @@ -0,0 +1,99 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file CppLog/output/OStreamWriter.h + * @author Ronald Kluth + * @date 2009/06/17 + * @brief Declaration and implementation of class template OStreamWriter + * @since 0.1 + */ + +#ifndef LOG_OUTPUT_OSTREAMWRITER_INCLUDED +#define LOG_OUTPUT_OSTREAMWRITER_INCLUDED + +#include "../Consumer.h" +#include "../Record.h" + +#include <ostream> +#include <sstream> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +namespace Log { + +/** + * @brief Simple log consumer implementation that writes records to a stream + * @tparam InfoListT List of info types to retrieve from log records + * + * This class is a very simple test output component. The @c consume method + * simply transforms each record into a plain text line. Info type elements + * are added automatically, according to the type list provided as template + * parameter. + */ +template < typename InfoListT = Detail::NullList > +class OStreamWriter : public Consumer< Record > +{ +public: + /// List of info types to retrieve from log records + typedef InfoListT InfoListType; + /// Pointer type to manage instances + typedef std::shared_ptr< OStreamWriter< InfoListType > > Ptr; + + /// Creation of OStreamWriter objects wrapped in a @c shared_ptr + static Ptr create( std::ostream& os ) + { + return Ptr( new OStreamWriter( os ) ); + } + + /// Redefinition of the log consumer interface method + virtual void consume( const Log::ChannelId channelId, const Record& record ) + { + if( ! record.getText().empty() ) + { + os_ << record.getText(); + } + MakeInfoString makeString; + record.iterateInfo< InfoListType >( makeString ); + + if( ! makeString.stream.str().empty() ) + { + os_ << " [Info:" << makeString.stream.str() << "]"; + } + os_ << std::endl; + } +private: + /// Construction, private, use @c create instead + OStreamWriter( std::ostream& os ): os_( os ) {} + +private: + /// Reference to the stream the log information is written to + std::ostream& os_; + +private: + /// Functor to transform record info into strings + struct MakeInfoString + { + std::ostringstream stream; + + template < typename InfoValueT > + void operator()( const Log::StringLiteral& name, const InfoValueT& value, bool found ) + { + if( found ) + { + stream << " " << name << "=" << value; + } + } + }; +}; + +} // namespace Log + +#endif /* LOG_OUTPUT_OSTREAMWRITER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/output/XmlFileWriter.h b/odemx-lite/external/CppLog/include/CppLog/output/XmlFileWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..295e4e9b521af37d140758c557c49660caf66fd7 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/output/XmlFileWriter.h @@ -0,0 +1,165 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file XmlFileWriter.h + * @author Ronald Kluth + * @date 2010/03/26 + * @brief Declaration and implementation of class template XmlFileWriter + * @since 0.1 + */ + +#ifndef LOG_OUTPUT_XMLFILEWRITER_INCLUDED +#define LOG_OUTPUT_XMLFILEWRITER_INCLUDED + +#include "../Record.h" +#include "XmlWriter.h" + +#include <cstddef> // size_t +#include <fstream> +#include <stdexcept> // runtime_error +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +namespace Log { + +/** + * @brief Simple log consumer implementation that writes records to an xml stream + * @tparam InfoListT List of info types to retrieve from log records + * + * This class is a simple XML-writing component. The @c consume method + * transforms each record into XML format by calling methods + * of the base class @c XmlWriter. Info type elements are added automatically, + * according to the type list provided as template parameter. + * + * As soon as the given file limit is reached, the current file is closed + * and a new one opened. For this purpose, the file name prefix is appended + * with a number. + * + * @note Be aware that string names of info types should not contain white space + * because these names are used as XML tag names. + */ +template < typename InfoListT = Detail::NullList > +class XmlFileWriter : public XmlWriter +{ +public: + /// List of info types to retrieve from log records + typedef InfoListT InfoListType; + /// Pointer type to manage XmlFileWriter objects + typedef std::shared_ptr< XmlFileWriter< InfoListType > > Ptr; + + /// Creation of XmlFileWriter objects wrapped in a @c shared_ptr + static Ptr create( const std::string& fileNamePrefix, std::size_t fileRecordLimit, + const std::string& root = "cpplog", unsigned int indent = 2 ) + { + return Ptr( new XmlFileWriter( fileNamePrefix, fileRecordLimit, root, indent ) ); + } + + /** + * @brief Destruction + * + * If the last XML file is still open, the root element is closed, + * as well as the file stream. + */ + virtual ~XmlFileWriter() + { + // finish the last file + if( fileStream_.is_open() ) + { + XmlWriter::closeElement( fileStream_, 0, rootElement_ ); + fileStream_.close(); + } + } + + /// Override of the log consumer interface method + virtual void consume( const Log::ChannelId channelId, const Record& record ) + { + if( fileRecordCount_ >= fileRecordLimit_ ) + { + startNewFile(); + } + + if( fileStream_.good() ) + { + XmlWriter::startElement( fileStream_, indent_, "record" ); + fileStream_ << std::endl; + if( ! record.getText().empty() ) + { + XmlWriter::writeElement( fileStream_, indent_ + indent_, "text", record.getText() ); + } + XmlWriter::StreamInfoElements addInfo( fileStream_, indent_ + indent_ ); + record.iterateInfo< InfoListType >( addInfo ); + XmlWriter::closeElement( fileStream_, indent_ , "record" ); + + ++fileRecordCount_; + } + } +private: + std::string fileNamePrefix_; + std::size_t fileRecordLimit_; + std::size_t fileRecordCount_; + std::size_t fileCount_; + std::ofstream fileStream_; + std::string rootElement_; + unsigned int indent_; + +private: + + /// Construction only via create() + XmlFileWriter( const std::string& fileNamePrefix, unsigned int fileRecordLimit, + const std::string& root = "cpplog", unsigned int indent = 2 ) + : fileNamePrefix_( fileNamePrefix ) + , fileRecordLimit_( fileRecordLimit ) + , fileRecordCount_( 0 ) + , fileCount_( 0 ) + , fileStream_() + , rootElement_( root ) + , indent_( indent ) + { + startNewFile(); + } + + void startNewFile() + { + // close root element and previous file stream + if( fileStream_.is_open() ) + { + XmlWriter::closeElement( fileStream_, 0, rootElement_ ); + fileStream_.close(); + } + + // create new file name + std::ostringstream fileName; + fileName << fileNamePrefix_ << "_" << fileCount_ << ".xml"; + + // reset the record counter and increase the file count + fileRecordCount_ = 0; + ++fileCount_; + + // reset stream flags and open new file + fileStream_.clear(); + fileStream_.open( fileName.str().c_str() ); + if( ! fileStream_.good() ) + { + throw std::runtime_error( std::string( + "XmlFileWriter::startNewFile(): failed to open file: " ) + + fileName.str() ); + } + + // start file with default XML header and open root element + XmlWriter::writeHeader( fileStream_ ); + XmlWriter::startElement( fileStream_, 0, rootElement_ ); + fileStream_ << std::endl; + } +}; + +} // namespace Log + +#endif /* LOG_OUTPUT_XMLFILEWRITER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/output/XmlStreamWriter.h b/odemx-lite/external/CppLog/include/CppLog/output/XmlStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..7c61df36d329e18a471c8ca518ffe938e900bb43 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/output/XmlStreamWriter.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file XmlStreamWriter.h + * @author Ronald Kluth + * @date 2010/03/26 + * @brief Declaration and implementation of class template XmlStreamWriter + * @since 0.1 + */ + +#ifndef LOG_OUTPUT_XMLSTREAMWRITER_INCLUDED +#define LOG_OUTPUT_XMLSTREAMWRITER_INCLUDED + +#include "../Record.h" +#include "XmlWriter.h" + +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +namespace Log { + +/** + * @brief Simple log consumer implementation that writes records to an XML stream + * @tparam InfoListT List of info types to retrieve from log records + * + * This class is a very simple XML output component. The @c consume method + * simply transforms each record into XML format by calling methods + * of the base class @c XmlWriter. Info type elements are added automatically, + * according to the type list provided as template parameter. + * + * @note Be aware that string names of info types should not contain white space + * because these names are used as XML tag names. + */ +template < typename InfoListT = Detail::NullList > +class XmlStreamWriter : public XmlWriter +{ +public: + /// List of info types to retrieve from log records + typedef InfoListT InfoListType; + /// Pointer type to manage instances + typedef std::shared_ptr< XmlStreamWriter< InfoListType > > Ptr; + + /// Creation of XmlStreamWriter objects wrapped in a @c shared_ptr + static Ptr create( std::ostream& os, unsigned int indent = 0 ) + { + return Ptr( new XmlStreamWriter( os, indent ) ); + } + + /// Destruction + virtual ~XmlStreamWriter() + { + } + + /// Implementation of the log consumer interface, transforms records to XML + virtual void consume( const Log::ChannelId channelId, const Record& record ) + { + if( os_.good() ) + { + XmlWriter::startElement( os_, indent_, "record" ); + os_ << std::endl; + if( ! record.getText().empty() ) + { + XmlWriter::writeElement( os_, indent_ + indent_, "text", record.getText() ); + } + XmlWriter::StreamInfoElements addInfo( os_, indent_ + indent_ ); + record.iterateInfo< InfoListType >( addInfo ); + XmlWriter::closeElement( os_, indent_, "record" ); + } + } +private: + /// Reference to the stream the log information is written to + std::ostream& os_; + /// Stores the number of spaces to be prepended before each line + unsigned int indent_; + +private: + /// Construction private, use create() instead + XmlStreamWriter( std::ostream& os, unsigned int indent = 0 ) + : os_( os ) + , indent_( indent ) + {} +}; + +} // namespace Log + +#endif /* LOG_OUTPUT_XMLSTREAMWRITER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/CppLog/output/XmlWriter.h b/odemx-lite/external/CppLog/include/CppLog/output/XmlWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..59d576cf5104c4bd2945aff0c9a6d13ded36e8b9 --- /dev/null +++ b/odemx-lite/external/CppLog/include/CppLog/output/XmlWriter.h @@ -0,0 +1,121 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file CppLog/output/XmlWriter.h + * @author Ronald Kluth + * @date 2010/03/25 + * @brief Declaration and implementation of abstract class XmlWriter + * @since 0.1 + */ + +#ifndef LOG_OUTPUT_XMLWRITER_INCLUDED +#define LOG_OUTPUT_XMLWRITER_INCLUDED + +#include "../detail/InfoTypeLoop.h" +#include "../Consumer.h" +#include "../StringLiteral.h" + +#include <ostream> +#include <string> + +namespace Log { + +/** + * @brief Abstract base class for consumers that write records to output streams in XML + * + * This base class provides XML output components with some basic + * static methods for creating correct XML markup strings. + * + * @note Be aware that string names of info types should not contain white space + * because these names are used as XML tag names. + */ +class XmlWriter : public Consumer< Record > +{ +public: + /// Construction + XmlWriter() + { + } + + /// Destruction + virtual ~XmlWriter() + { + } + + /// Prints start tag to the stream: <element> + static void startElement( std::ostream& os, unsigned int indent, + std::string const& tag ) + { + os << std::string( indent, ' ' ) << "<" << tag << ">"; + } + + /// Prints close tag to the stream: </element> + static void closeElement( std::ostream& os, unsigned int indent, + std::string const& tag ) + { + os << std::string( indent, ' ' ) << "</" << tag << ">" << std::endl; + } + + /// Prints an empty element to the stream: <element/> + static void emptyElement( std::ostream& os, unsigned int indent, + std::string const& tag ) + { + os << std::string( indent, ' ' ) << "<" << tag << "/>" << std::endl; + } + + /// Prints a complete element to the stream: <element>value</element> + template< typename ValueT > + static void writeElement( std::ostream& os, unsigned int indent, + std::string const& tag, ValueT const& value ) + { + startElement( os, indent, tag ); + os << value; + closeElement( os, 0, tag ); + } + + /// Prints an XML header to the stream to start a document + static void writeHeader( std::ostream& os ) + { + os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; + } +private: + /// Non-copyable + XmlWriter( XmlWriter const& ); + /// Non-assignable + XmlWriter& operator=( XmlWriter const& ); + +protected: + /// Functor that transforms record info into XML elements and writes them to a stream + struct StreamInfoElements + { + std::ostream& stream_; + unsigned int indent_; + + StreamInfoElements( std::ostream& stream, unsigned int indent ) + : stream_( stream ) + , indent_( indent ) + {} + + template < typename InfoValueT > + void operator()( Log::StringLiteral const& name, InfoValueT const& value, bool found ) + { + if( found ) + { + writeElement( stream_, indent_, name.c_str(), value ); + } + else + { + emptyElement( stream_, indent_, name.c_str() ); + } + } + }; +}; + +} // namespace Log + +#endif /* LOG_OUTPUT_XMLWRITER_INCLUDED */ diff --git a/odemx-lite/external/CppLog/include/setup.h b/odemx-lite/external/CppLog/include/setup.h new file mode 100644 index 0000000000000000000000000000000000000000..e7f7951febc12d7cc61fec6197ff25d50c4b6a51 --- /dev/null +++ b/odemx-lite/external/CppLog/include/setup.h @@ -0,0 +1,75 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file include/setup.h + * @author Ronald Kluth + * @date 2010/04/24 + * @brief Preprocessor macros for compiling CppLog with different settings + * @since 0.1 + */ + +#ifndef CPPLOG_SETUP_INCLUDED +#define CPPLOG_SETUP_INCLUDED + +/** + * @def CPPLOG_USE_DATABASE + * @brief Enables the component DatabaseAccessor + * + * The database component requires the library POCO Data. Hence, this + * define should only be activated when POCO is present in the compiler's + * include path. + */ +//#define CPPLOG_USE_DATABASE + +/** + * @def CPPLOG_USE_SQLITE + * @brief Enables the SQLite database connectivity + * + * The default database management system is the embedded library SQLite + * that comes with POCO Data. It is enabled by using this define. + */ +//#define CPPLOG_USE_SQLITE + +/** + * @def CPPLOG_USE_ODBC + * @brief Enables the ODBC database connectivity + * + * POCO's ODBC-Connector can be used by enabling this define. Some Methods + * of class DatabaseAccessor will need other defines to be enabled, which + * specify the external database. + * + * @see CPPLOG_USE_SQLITE, CPPLOG_USE_POSTGRESQL + */ +//#define CPPLOG_USE_ODBC + +/** + * @def CPPLOG_USE_POSTGRESQL + * @brief Enables ODBC and some PostgreSQL-specific SQL syntax + * + * Since all DBMS use different SQL dialects it became necessary to make the + * distinction between specific databases in order to enable some concurrency + * functionality. + * + * @see CPPLOG_USE_SQLITE, CPPLOG_USE_ODBC + */ +//#define CPPLOG_USE_POSTGRESQL + +//------------------------------------------------------------------dependencies + +// if any of the database defines is enabled, compile DatabaseAccessor +#ifdef CPPLOG_USE_SQLITE + #define CPPLOG_USE_DATABASE +#endif + +// if PostgreSQL is enabled, enable DatabaseAccessor and ODBC +#ifdef CPPLOG_USE_POSTGRESQL + #define CPPLOG_USE_DATABASE + #define CPPLOG_USE_ODBC +#endif + +#endif /* CPPLOG_SETUP_INCLUDED */ diff --git a/odemx-lite/external/CppLog/src/samples/CppLogSamples.kdev4 b/odemx-lite/external/CppLog/src/samples/CppLogSamples.kdev4 new file mode 100644 index 0000000000000000000000000000000000000000..4686551f50257c3a90bda6c56e010702c44ff114 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/CppLogSamples.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCustomMakeManager +Name=CppLogSamples diff --git a/odemx-lite/external/CppLog/src/samples/Makefile b/odemx-lite/external/CppLog/src/samples/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..32ba97feccfd560d0bb1ef58f20ebd6791e47c04 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/Makefile @@ -0,0 +1,81 @@ +# +# Copyright (c) 2009-2010 Ronald Kluth +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +all: samples + +#---------------------------------------------------------customizable variables + +BUILD_DIR = build + +SOURCE_DIR = src + +# POCO_BASE_DIR = /home/ron/Develop/KDev4Projects/poco.rev.1217 +POCO_BASE_DIR = ../../../poco.rev.1094 + +CXX_DEBUG_FLAGS = -Wall -O0 -g3 -pg -Wno-sign-compare +CXX_RELEASE_FLAGS = -Wall -O3 -Wno-sign-compare + +INC_PATHS = \ +-I ../../include \ +-I $(POCO_BASE_DIR)/Foundation/include \ +-I $(POCO_BASE_DIR)/Data/include \ +-I $(POCO_BASE_DIR)/Data/SQLite/include \ +-I $(POCO_BASE_DIR)/Data/ODBC/include + +DEBUG_LIBS = \ +-l PocoXMLd \ +-l PocoSQLited \ +-l PocoODBCd \ +-l PocoDatad \ +-l PocoFoundationd \ +-l odbc \ +-l pthread \ +-l dl + +RELEASE_LIBS = \ +-l PocoXML \ +-l PocoSQLite \ +-l PocoODBC \ +-l PocoData \ +-l PocoFoundation \ +-l odbc \ +-l pthread \ +-l dl + + +LIB_PATH = \ +-L $(POCO_BASE_DIR)/lib +#-L $(POCO_BASE_DIR)/lib/Linux/x86_64 + +CXX_FLAGS = $(CXX_RELEASE_FLAGS) +LIBS = $(RELEASE_LIBS) + +#-----------------------------------------------------------------automatic part + +# get all sources +VPATH := $(SOURCE_DIR) + +# compute targets +TARGETS := $(patsubst $(SOURCE_DIR)/%.cpp, $(BUILD_DIR)/%, $(wildcard $(SOURCE_DIR)/*.cpp)) + +# create build directory +build_dir: + @echo "Creating build directory: $(BUILD_DIR)" + @mkdir -p $(BUILD_DIR) + +# a rule to make all samples at once +samples: build_dir $(TARGETS) + +# build targets from sources +$(BUILD_DIR)/%: %.cpp + @echo "Compiling $< to target: $@" + @$(CXX) $(CXX_FLAGS) $(INC_PATHS) $(LIB_PATH) -o $@ $< $(LIBS) + +# clean build by removing +clean: + @echo "Removing build directory: $(BUILD_DIR)" + @rm -rf $(BUILD_DIR) diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Channel_Consumer.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Channel_Consumer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef2a1ea3b107cafba56c81540a9ca7db87e1a83c --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Channel_Consumer.cpp @@ -0,0 +1,66 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Example_Channel_Consumer.cpp + * @author Ronald Kluth + * @date 2009/11/22 + * @brief Example introducing basic channel and consumer usage + * @since 0.1 + */ + +/** + * @example Example_Channel_Consumer.cpp + * + * This example introduces basic channel usage with a custom consumer class. + * The consumer class @c %ConsoleWriter simply disregards the channel ID and + * prints the record string to the console. + * + * The main function shows the use of a channel object and a @c shared_ptr + * -managed channel using @c std::string as record type. First, a consumer + * is created, which is registered to a channel object. The following log + * record is then printed to the console. + * + * Wrapping the channel in a + * @c shared_ptr provides a few more options. When the pointer is set, the + * record is forwarded to the console as expected. However, resetting the + * pointer disables logging through that channel because the pointer is checked + * in @c operator<<. However, the call to the operator still requires the + * record object to be created. This overhead can also be avoided by checking + * the pointer before even making the logging call, as is shown in the last + * statement. + */ + +#include <CppLog.h> +#include <iostream> + +typedef std::string Rec; + +class ConsoleWriter: public Log::Consumer< Rec > { +public: + virtual void consume( const Log::ChannelId channelId, const Rec& record ) { + std::cout << record << std::flush; + } +}; + +int main() { + typedef std::shared_ptr< Log::Channel< Rec > > ChannelPtr; + typedef std::shared_ptr< Log::Consumer< Rec > > ConsumerPtr; + ConsumerPtr consoleWriter = ConsumerPtr( new ConsoleWriter() ); + + Log::Channel< Rec > channel; + channel.addConsumer( consoleWriter ); + channel << Rec( "Logging via Channel object\n" ); + + ChannelPtr p_channel( new Log::Channel< Rec >() ); + p_channel->addConsumer( consoleWriter ); + p_channel << Rec( "Logging via set Channel pointer produces output\n" ); + p_channel.reset(); + p_channel << Rec( "Logging via empty pointer prints nothing\n" ); + if( p_channel ) + p_channel << Rec( "Checking empty pointer avoids record creation\n" ); +} diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Consumer_Sqlite.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Consumer_Sqlite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6084cbedc382f67e9137bd367494ba58f9db221 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Consumer_Sqlite.cpp @@ -0,0 +1,141 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file src/Example_Consumer_Sqlite.cpp + * @author Ronald Kluth + * @date 2009/11/28 + * @brief Example showing the usage of DatabaseAccessor as consumer member + * @since 0.1 + */ + +/** + * @example src/Example_Consumer_Sqlite.cpp + * + * This example demonstrates how to write a custom consumer class that + * logs records to an SQLite database. It makes use of the library's + * default @c Record type to transport arbitrary information in log records. + * These so-called info types @c I1, @c I2, and @c I3 will be stored in table + * columns named like the string parameter provided in their declaration with + * the macro @c CPPLOG_DECLARE_INFO_TYPE. The subsequently declared list of + * info types @c Infos is used to iterate over the info types during database + * table creation and the insertion of records. + * + * The consumer class @c SqliteWriter is initialized with a database file name + * and a buffer limit. For connecting and communicating with the database, + * a @c DatabaseAccessor object is used. To further speed up the insertion of + * records, an @c SqlInserter object is used, which holds a prepared statement, + * thus avoiding SQL parsing overhead. For convenience, the accessor provides + * method templates that iterate the info list and extract the necessary + * information automatically. The macro @c CPPLOG_DECLARE_SQL_COLUMN_TYPES is + * used to provide the SQL data types to be used in columns that store info + * types. + * + * During initialization, the database table is created if + * it does not exist, and the inserter is initialized. When the buffer limit is + * reached in @c consume, the buffered log records are efficiently written to + * the database in one transaction by calling @c flush. The insertion is + * implemented by providing the buffer and an insert functor as parameters to + * the accessor's @c storeData method. + * + * In the main function, a channel object is created and an @c SqliteWriter is + * registered as consumer. Afterwards, a large number of records is created and + * sent via the channel. One final call to @c flush is made to store any + * remaining data from the buffer. Since the database functionality is + * implemented on top of the Poco.Data library, we added a @c try-catch block + * to handle possible exceptions. + */ + +#define CPPLOG_USE_SQLITE + +#include <CppLog.h> +#include <iostream> +using namespace Log; + +CPPLOG_DECLARE_INFO_TYPE( I1, "info_1", std::string ); +CPPLOG_DECLARE_INFO_TYPE( I2, "info_2", int ); +CPPLOG_DECLARE_INFO_TYPE( I3, "info_3", float ); +CPPLOG_DECLARE_INFO_TYPE_LIST( Infos, I1, I2, I3 ); + +class SqliteWriter: public Consumer<> { +public: + SqliteWriter( const std::string& dbFileName, std::size_t bufferLimit ) + : db_( dbFileName ), bufferLimit_( bufferLimit ), + recordCount_( 0 ), initialized_( false ) + {} + void flush(); +private: + virtual void consume( const ChannelId channelId, const Record& record ); + void initialize(); + void insert( const Record& record ); +private: + DatabaseAccessor db_; + std::auto_ptr< DatabaseAccessor::SqlInserter > inserter_; + std::vector< Record > buffer_; + std::size_t bufferLimit_, recordCount_; + bool initialized_; +}; + +void SqliteWriter::consume( const ChannelId channelId, const Record& record ) { + if( ! initialized_ ) initialize(); + + if( recordCount_ < bufferLimit_ ) { + ++recordCount_; + } else { + flush(); + recordCount_ = 0; + } + buffer_.push_back( record ); +} + +CPPLOG_DECLARE_SQL_COLUMN_TYPES( Infos, sqlTypes, "VARCHAR", "INTEGER", "REAL" ); + +void SqliteWriter::initialize() { + if( ! db_.tableExists( "log_record" ) ) { + db_.createTable( "log_record" ) + .column( "id", "INTEGER" ) + .column( "text", "VARCHAR" ) + .columns< Infos >( sqlTypes ) + .primaryKey( "id" ); + } + inserter_ = db_.createInserter(); + inserter_->table( "log_record" ) + .column( "text" ) + .columns< Infos >(); + initialized_ = true; +} + +void SqliteWriter::flush() { + using namespace std; + db_.storeData( buffer_, bind( &SqliteWriter::insert, this, placeholders::_1 ) ); + buffer_.clear(); +} + +void SqliteWriter::insert( const Record& record ) { + inserter_->value( record.getText().c_str() ) + .values< Infos >( record ) + .execute(); +} + +int main() { + try { + typedef std::shared_ptr< SqliteWriter > SqlitePtr; + SqlitePtr sqlite( new SqliteWriter( "Example_Consumer_Sqlite.db", 100000 ) ); + + Channel<> channel; + channel.addConsumer( sqlite ); + + int i = 100000; + while( i-- ) + { + channel << Record( "Logging example: SQLite database access" ) + + I1( "string detail" ) + I2( 2 ) + I3( 3.0f ); + } + sqlite->flush(); + } + catch( const Poco::Exception& ex ) { std::cout << ex.displayText(); } +} diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_DatabaseAccessor.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_DatabaseAccessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b1be38bed6f90bc4651fb4f71e81f8f9ed71271 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_DatabaseAccessor.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Example_DatabaseAccessor.cpp + * @author Ronald Kluth + * @date 2009/11/29 + * @brief Example showing the usage of DatabaseAccessor with SQLite + * @since 0.1 + */ + +/** + * @example Example_DatabaseAccessor.cpp + * + * This example demonstrates how to use class @c DatabaseAccessor for writing + * data to an SQLite database. The record type is a pair of ID and string. + * The function @c insertRow defines how to write a single record to the + * database by using the accessor's method @c insertIntoTable. + * + * In the main program we first use the method @c tableExists to check if + * the table is already contained in the database. If not, it is created + * via the method @c createTable. We then retrieve the current maximum ID + * value in order to create valid primary keys for new records. After that, + * two records are added to a buffer and finally, the buffer is written to + * the database by calling @c storeData and providing the buffer and the + * function @c insertRow, which is called for every buffered record. + */ + +#define CPPLOG_USE_SQLITE + +#include <CppLog.h> +#include <string> +#include <utility> +#include <vector> +using namespace std; + +Log::DatabaseAccessor db( "example.db" ); + +void createTable() +{ + if( ! db.tableExists( "example_table" ) ) + { + db.createTable( "example_table" ) + .column( "id", "INTEGER" ) + .column( "text", "VARCHAR" ) + .primaryKey( "id" ); + } +} + +void insertRow( const pair< int, string >& record ) +{ + db.insertIntoTable( "example_table" ) + .columnValue( "id", record.first ) + .columnValue( "text", record.second ); +} + +int main() +{ + createTable(); + + int maxId; + db.getMaxColumnValue( "example_table", "id", maxId ); + + vector< pair< int, string > > buffer; + buffer.push_back( make_pair( maxId + 1, "first_example_string" ) ); + buffer.push_back( make_pair( maxId + 2, "second_example_string" ) ); + + db.storeData( buffer, &insertRow ); +} diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Filter.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78d2f275ac1af44de9d1b0db9238725e8aba7019 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Filter.cpp @@ -0,0 +1,52 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file src/Example_Filter.cpp + * @author Ronald Kluth + * @date 2009/11/29 + * @brief Example introducing basic filter usage + * @since 0.1 + */ + +/** + * @example src/Example_Filter.cpp + * + * This example illustrates the basic usage of record filters. Since @c Filter + * is only an interface, we use the filter specialization for the library's + * default record type. Filtering of @c Record objects is based on filter sets + * for the record text and each info type. + * + * Filter entries are added in a stream-like manner + * with @c operator<< to filter sets retrieved by the method template @c add. + * Filtering happens when a log record passes the channel inserter + * (@c operator<<), which checks the channel for a filter and, if one is set, + * whether the record may pass. In this example we filter records + * by the @c ScopeInfo value "foo()", which means that all records originating + * from the function @c foo are blocked. + */ + +#include <CppLog.h> +#include <iostream> +using namespace Log; + +CPPLOG_DECLARE_INFO_TYPE_LIST( Infos, ScopeInfo ); +Channel<> channel; + +void foo() { + channel << Record( "Logging filter example (foo)" ) + ScopeInfo( "foo()" ); +} + +int main() { + std::shared_ptr< Filter<> > filter = Filter<>::create(); + filter->add< ScopeInfo >() << "foo()"; + channel.setFilter( filter ); + channel.addConsumer( OStreamWriter< Infos >::create( std::cout ) ); + + channel << Record( "Logging filter example (main)" ) + ScopeInfo( "main()" ); + foo(); +} diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Logging_StringLiteral.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Logging_StringLiteral.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60738bedf2278c212d7944f92d2040cb5d2958fc --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Logging_StringLiteral.cpp @@ -0,0 +1,96 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Example_Logging_StringLiteral.cpp + * @author Ronald Kluth + * @date 2009/04/11 + * @brief Example displaying use of CppLog with normal C-strings + * @since 0.1 + */ + +/** + * @example Example_Logging_StringLiteral.cpp + * + * This example illustrates how to log data with the simplest and fastest + * kind of strings - constant string literals. In order to do this we + * define Log::StringLiteral as the record type. To be able to use simple + * C-strings without constructor calls to Log::StringLiteral, another + * overload of @c operator<< must be provided that transforms const char[] + * to a Log::StringLiteral and writes it to the channel. + * + */ +#include <CppLog.h> +#include <iostream> +// +//------------------------------------------------------------------------global +// +// To log strings, the simplest log records are sufficient. +// +typedef Log::StringLiteral Rec; +// +// In order to create log records from string literals, we must overload the +// insertion operator for fixed-length character arrays. +// +template < std::size_t LenV > +const Log::Channel< Rec >& +operator<<( const Log::Channel< Rec >& channel, const char (&recordText)[LenV] ) +{ + // + // The record text is used to create a simple StringLiteral record for + // each logged string, which is then sent through the channel via + // Log::operator<<. + // + channel << Rec( recordText ); + return channel; +} +// +// For simplicity, we use a global log channel object. +// +Log::Channel< Rec > logChannel; +// +//-----------------------------------------------------------------------classes +// +// To receive and handle log records, we subclass the DataConsumer interface +// with the appropriate record type and implement the method 'consume()' +// In this example, we print formatted records to the console. +// +class ConsoleWriter +: public Log::Consumer< Rec > +{ +public: + // + // Override the pure virtual method 'consume()'. The second parameter + // uses a typedef from the base class DataConsumer to free us from + // using possibly complicated record type names. + // + virtual void consume( const Log::ChannelId channelId, const Rec& record ) + { + std::cout << record << std::flush; + } +}; +// +//--------------------------------------------------------------------------main +// +int main( int argc, char* argv[] ) +{ + // + // We register an instance of ConsoleWriter with the channel. + // + logChannel.addConsumer( std::shared_ptr< ConsoleWriter >( new ConsoleWriter() ) ); + // + // Now, we can start logging right away by sending strings to the channel, + // which basically forwards them to stdout. + // + logChannel << "a string literal followed by some value: " << "2" << "\n"; + return 0; +} +// +//----------------------------------------------------------------program output +// +//a string record displaying some value: 2 +// diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Producer_ChannelManager.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Producer_ChannelManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..813837e1b65f3a3baaa0fd533092a8c5550c52c1 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Producer_ChannelManager.cpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Example_Producer_ChannelManager.cpp + * @author Ronald Kluth + * @date 2009/11/22 + * @brief Example introducing basic producer and channel manager usage + * @since 0.1 + */ + +/** + * @example Example_Producer_ChannelManager.cpp + * + * This example illustrates the basic usage of the class templates @c Producer + * and @c ChannelManager. First, the record type is defined as a pair of two + * strings, followed by the declaration of two channels: @c info and @c debug. + * The IDs of the channels are used to enable channel members within the + * @c Producer template by providing an instance of @c Enable as template + * parameter. By deriving from the resulting type, class @c ExampleProducer + * can access the two channel members @c info and @c debug directly. + * + * Since a user-defined record type is employed, we must provide a suitable + * consumer type: the class @c ConsoleWriter. It uses the channel IDs to + * print information about the forwarding channel. + * + * In the main function, a @c ChannelManager is created, which is used in the + * initialization of two producer objects. By adding a consumer to the manager, + * it is automatically registered with all currently managed channels, and + * the records sent by both producers are printed on the console. + */ + +#include <CppLog.h> +#include <iostream> + +typedef std::pair< std::string, std::string > Rec; + +CPPLOG_DECLARE_CHANNEL_WITH_ID( channel, info, Rec, 1 ); +CPPLOG_DECLARE_CHANNEL_WITH_ID( channel, debug, Rec, 2 ); + +typedef Log::Producer< Log::Enable< channel::info, channel::debug > > ProducerType; + +class DataProducer: public ProducerType { +public: + DataProducer( Log::ChannelManager< Rec >& mgr, const std::string& name ) + : ProducerType( mgr , name ) {} + void useInfo() { + info << log( "Info logging with Producer and ChannelManager" ); + } + void useDebug() { + debug << log( "Debug logging with Producer and ChannelManager" ); + } +private: + Rec log( const std::string& text ) const { return Rec( getName(), text ); } +}; + +class ConsoleWriter: public Log::Consumer< Rec > { +public: + virtual void consume( const Log::ChannelId channelId, const Rec& record ) { + switch( channelId ) { + case channel::info: std::cout << "INFO "; break; + case channel::debug: std::cout << "DEBUG "; break; + default: break; + } + std::cout << "(" << record.first << ") " << record.second << std::endl; + } +}; + +int main() { + typedef std::shared_ptr< Log::Consumer< Rec > > ConsumerPtr; + Log::ChannelManager< Rec > manager; + DataProducer p1( manager, "P1" ), p2( manager, "P2" ); + manager.addConsumer( ConsumerPtr( new ConsoleWriter() ) ); + p1.useInfo(); + p2.useDebug(); +} diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Record.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Record.cpp new file mode 100644 index 0000000000000000000000000000000000000000..845eb29e0508120746f73fe71c6ff06fd06d703a --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Record.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Example_Record.cpp + * @author Ronald Kluth + * @date 2009/11/23 + * @brief Example introducing basic default record usage + * @since 0.1 + */ + +/** + * @example Example_Record.cpp + * + * This example illustrates the basic usage of the library's default record + * type. Class @c Record always holds a text message, but it can also be used + * to transport arbitrary data. All that is necessary is a declaration of a + * so-called info type with the macro CPPLOG_DECLARE_INFO_TYPE. The library + * already provides three common info types: @c FileInfo, @c LineInfo, and + * @c ScopeInfo, all of which are used in this example. Additionally, a list + * of info types can be declared to provide automatic iteration over the + * contained information. This is done via the macro CPPLOG_DECLARE_INFO_TYPE_LIST. + * + * After declaring the list @c Infos of info types, we add the functor + * @c InfoWriter for printing info type values on the console. In the main + * function, we first create a record object with a text message and then + * add the info types with the class's methods @c file, @c line, and @c scope + * which all support chaining. + * + * The next part shows two different ways to extract information from @c Record + * objects. The text can be retrieved via @c getText, but the info types need a + * little more work as they are stored in a map with their type info as key. + * Hence they must be requested via the method template @c get, which returns + * a pointer to the data, or zero if the given info type was not found in the + * record. The other method is automatic iteration over info types via the + * method template @c iterateInfo, which requires an info type list and a + * functor to call for each value. + */ +#include <CppLog.h> +#include <iostream> +using namespace Log; + +CPPLOG_DECLARE_INFO_TYPE_LIST( Infos, FileInfo, LineInfo, ScopeInfo ); + +struct InfoWriter { + template < typename ValT > + void operator()( const StringLiteral& name, const ValT& value, bool found ) { + if( found ) { std::cout << ", " << name << ": " << value; } + } +} writer; + +int main() { + Record rec( "Logging class Record example" ); + rec.file( __FILE__ ).line( __LINE__ ).scope( "main()" ); + + std::cout << rec.getText(); + if( FileInfo::Type const* fi = rec.get< FileInfo >() ) + std::cout << ", " << FileInfo::getName() << ": " << *fi; + if( LineInfo::Type const* li = rec.get< LineInfo >() ) + std::cout << ", " << LineInfo::getName() << ": " << *li; + if( ScopeInfo::Type const* si = rec.get< ScopeInfo >() ) + std::cout << ", " << ScopeInfo::getName() << ": " << *si; + std::cout << std::endl; + + std::cout << rec.getText(); + rec.iterateInfo< Infos >( writer ); + std::cout << std::endl; +} diff --git a/odemx-lite/external/CppLog/src/samples/src/Example_Record_TextWriters.cpp b/odemx-lite/external/CppLog/src/samples/src/Example_Record_TextWriters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4211f2f3366de8ced14d4c8754431f04216dd18 --- /dev/null +++ b/odemx-lite/external/CppLog/src/samples/src/Example_Record_TextWriters.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file Example_Record_TextWriters.cpp + * @author Ronald Kluth + * @date 2009/11/23 + * @brief Example introducing default text writers + * @since 0.1 + */ + +/** + * @example Example_Record_TextWriters.cpp + * + * This example demonstrates the use of the library's default text writing + * components. To illustrate how they can be used with any class that provides + * a stream inserter overload (@c operator<<), we first define a structure + * @c Point3d and two info types @c PointInfo and @c DoubleInfo. These are then + * added to the list @c Infos, which we plan to extract automatically from the + * log records. + * + * In the main function we create a channel object an register two consumers: + * an @c OStreamWriter which is connected to the console, and an @c XmlFileWriter + * which will store all records in XML files. The second parameter sets a record + * limit per file. When the limit is reached, a new XML file is created + * automatically. The output of the log record in the last statement will appear + * on the console and in a file called @c Example_0.xml. The added @c Point3d + * is converted into a string by means of @c operator<<. + */ + +#include <CppLog.h> +#include <iostream> + +struct Point3d { float x, y, z; }; + +std::ostream& operator<<( std::ostream& os, Point3d const& p ) { + os << "(" << p.x << " " << p.y << " " << p.z << ")"; + return os; +} + +CPPLOG_DECLARE_INFO_TYPE( PointInfo, "point", Point3d ); +CPPLOG_DECLARE_INFO_TYPE( DoubleInfo, "value", double& ); +CPPLOG_DECLARE_INFO_TYPE_LIST( Infos, PointInfo, DoubleInfo ); + +int main() { + Log::Channel<> channel; + channel.addConsumer( Log::OStreamWriter< Infos >::create( std::cout ) ); + channel.addConsumer( Log::XmlStreamWriter< Infos >::create( std::cout ) ); + channel.addConsumer( Log::XmlFileWriter< Infos >::create( "Example", 1000 ) ); + + Point3d p = { 1, 2, 3 }; + channel << Log::Record() + PointInfo( p ) + DoubleInfo( 123.45 ); +} diff --git a/odemx-lite/external/CppLog/src/test/CppLogTest.kdev4 b/odemx-lite/external/CppLog/src/test/CppLogTest.kdev4 new file mode 100644 index 0000000000000000000000000000000000000000..9caa8cdee471d2eac18aee384b5b849e0bfc0be4 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/CppLogTest.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCustomMakeManager +Name=CppLogTest diff --git a/odemx-lite/external/CppLog/src/test/Makefile b/odemx-lite/external/CppLog/src/test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0d11d8bc83192430bcf5c835c51e347537d529ad --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/Makefile @@ -0,0 +1,70 @@ +all: testing + +#---------------------------------------------------------customizable variables + +TARGET = TestCppLog + +BUILD_DIR = build + +SOURCE_DIR = src + +CXX_FLAGS = -g3 -Wall -Wno-sign-compare + +UNITTEST_PP_DIR = ../../../UnitTest++ +POCO_BASE_DIR = ../../../poco.rev.1094 + +INC_PATHS = \ +-I ../../include \ +-I $(UNITTEST_PP_DIR)/src \ +-I $(POCO_BASE_DIR)/Foundation/include \ +-I $(POCO_BASE_DIR)/Data/include \ +-I $(POCO_BASE_DIR)/Data/SQLite/include + +LIB_PATHS = \ +-L $(UNITTEST_PP_DIR) \ +-L $(POCO_BASE_DIR)/lib + +LIBS = \ +-l UnitTest++ \ +-l PocoSQLited \ +-l PocoDatad \ +-l PocoFoundationd \ +-l pthread \ +-l dl + +#-----------------------------------------------------------------automatic part + +# get all sources +VPATH := $(SOURCE_DIR) + +# compute objects +OBJECTS := $(patsubst $(SOURCE_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(wildcard $(SOURCE_DIR)/*.cpp)) + +# create build directory +build_dir: + @echo "Creating build directory: $(BUILD_DIR)" + @mkdir -p $(BUILD_DIR) + +# build objects from sources +$(BUILD_DIR)/%.o: %.cpp + @echo "Compiling $< to target: $@" + @$(CXX) $(CXX_FLAGS) -c $< $(INC_PATHS) -o $@ + +# link objects to executable +test_runner: build_dir $(OBJECTS) + @echo "Creating executable: $(BUILD_DIR)/$(TARGET)" + @$(CXX) -o $(BUILD_DIR)/$(TARGET) $(OBJECTS) $(LIB_PATHS) $(LIBS) + +# preparations for testing +prep: + @rm -f $(BUILD_DIR)/*.db + +# run all tests automatically +testing: prep test_runner + @echo "Running tests..." + @cd $(BUILD_DIR); ./$(TARGET); + +# clean build by removing +clean: + @echo "Removing build directory: $(BUILD_DIR)" + @rm -rf $(BUILD_DIR) diff --git a/odemx-lite/external/CppLog/src/test/src/TestChannel.cpp b/odemx-lite/external/CppLog/src/test/src/TestChannel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85fe8f215cc4617838a4fb8501f827f954b7f626 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestChannel.cpp @@ -0,0 +1,111 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestChannel.cpp + * @author Ronald Kluth + * @date created at 2009/05/16 + * @brief Unit tests for class template Channel + * @since 0.1 + */ + +#include "global.h" +#include <string> + +SUITE( CppLogUnitTest ) +{ + template< typename RecordT > + struct DummyConsumer: public Log::Consumer< RecordT > + { + virtual void consume( const Log::ChannelId channelId, const RecordT& record ) + { + lastChannelId = channelId; + lastRecord = record; + } + Log::ChannelId lastChannelId; + RecordT lastRecord; + }; + + struct TestChannelFixture + { + typedef Log::Channel< std::string > Channel; + typedef std::shared_ptr< Channel > ChannelPtr; + typedef Log::Filter< std::string > Filter; + typedef std::shared_ptr< Filter > FilterPtr; + typedef DummyConsumer< std::string > Consumer; + typedef std::shared_ptr< Consumer > ConsumerPtr; + + TestChannelFixture() + : channelId( 99 ) + , channel( channelId ) + {} + + Log::ChannelId channelId; + Channel channel; + }; + + TEST_FIXTURE( TestChannelFixture, Id ) + { + CHECK_EQUAL( channel.getId(), channelId ); + } + + TEST_FIXTURE( TestChannelFixture, Filter ) + { + FilterPtr filter( new Filter() ); + channel.setFilter( filter ); + CHECK( channel.hasFilter() ); + CHECK_EQUAL( filter, channel.getFilter() ); + + channel.resetFilter(); + CHECK( ! channel.hasFilter() ); + } + + TEST_FIXTURE( TestChannelFixture, Consumers ) + { + ConsumerPtr con1( new Consumer() ); + ConsumerPtr con2( new Consumer() ); + ConsumerPtr con3( new Consumer() ); + channel.addConsumer( con1 ); + channel.addConsumer( con2 ); + channel.addConsumer( con3 ); + + const Channel::ConsumerSet& cons = channel.getConsumers(); + CHECK( cons.find( con1 ) != cons.end() ); + CHECK( cons.find( con2 ) != cons.end() ); + CHECK( cons.find( con3 ) != cons.end() ); + + channel.removeConsumer( con2 ); + CHECK( cons.find( con1 ) != cons.end() ); + CHECK( cons.find( con2 ) == cons.end() ); + CHECK( cons.find( con3 ) != cons.end() ); + + channel.removeConsumers(); + CHECK( cons.empty() ); + } + + TEST_FIXTURE( TestChannelFixture, Inserters ) + { + ConsumerPtr con( new Consumer() ); + channel.addConsumer( con ); + std::string record( "Channel Object Inserter Test" ); + channel << record; + CHECK_EQUAL( record, con->lastRecord ); + CHECK_EQUAL( channel.getId(), con->lastChannelId ); + + ChannelPtr p_channel( new Channel( channelId + 1 ) ); + p_channel->addConsumer( con ); + record = "Channel Pointer Inserter Test"; + p_channel << record; + CHECK_EQUAL( record, con->lastRecord ); + CHECK_EQUAL( p_channel->getId(), con->lastChannelId ); + + p_channel.reset(); + record.clear(); + p_channel << record; + CHECK( ! con->lastRecord.empty() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestChannelManager.cpp b/odemx-lite/external/CppLog/src/test/src/TestChannelManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d7406058a12ba737b95eabc16c8e602a36325f8 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestChannelManager.cpp @@ -0,0 +1,124 @@ +// +// Copyright (c) 2009-2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestChannelManager.cpp + * @author Ronald Kluth + * @date created at 2010/04/17 + * @brief Unit tests for class template Channel + * @since 0.1 + */ + +#include "global.h" +#include <string> + +SUITE( CppLogUnitTest ) +{ + struct DummyConsumer: public Log::Consumer<> + { + virtual void consume( const Log::ChannelId channelId, const Log::Record& record ) {} + }; + + struct ChannelManagerFixture + { + typedef Log::Channel<> Channel; + typedef std::shared_ptr< Channel > ChannelPtr; + typedef DummyConsumer Consumer; + typedef std::shared_ptr< Consumer > ConsumerPtr; + typedef Log::Filter<> Filter; + typedef std::shared_ptr< Filter > FilterPtr; + + ChannelManagerFixture() + : manager( ) + , id1( 123 ) + , id2( 456 ) + {} + + Log::ChannelManager<> manager; + Log::ChannelId id1; + Log::ChannelId id2; + }; + + TEST( ChannelManagerNameScopeDefaults ) + { + std::string defaultName = "No label given"; + char defaultSpacer = ' '; + Log::ChannelManager<> manager( defaultName, defaultSpacer ); + std::string emptyName = manager.createUniqueName( "" ); + std::string emptyName1 = manager.createUniqueName( "" ); + + CHECK_EQUAL( defaultName, emptyName ); + CHECK_EQUAL( defaultSpacer, emptyName1[ defaultName.size() ] ); + } + + TEST_FIXTURE( ChannelManagerFixture, GetChannel ) + { + ChannelPtr c1 = manager.getChannel( id1 ); + CHECK( (bool)c1 ); + ChannelPtr c2 = manager.getChannel( id1 ); + CHECK_EQUAL( c1, c2 ); + } + + TEST_FIXTURE( ChannelManagerFixture, AddConsumer ) + { + ConsumerPtr con( new Consumer() ); + ChannelPtr c1 = manager.getChannel( id1 ); + manager.addConsumer( id1, con ); + CHECK_EQUAL( 1, c1->getConsumers().size() ); + CHECK( c1->getConsumers().find( con ) != c1->getConsumers().end() ); + + ConsumerPtr con2( new Consumer() ); + ChannelPtr c2 = manager.getChannel( id2 ); + manager.addConsumer( con2 ); + CHECK_EQUAL( 2, c1->getConsumers().size() ); + CHECK_EQUAL( 1, c2->getConsumers().size() ); + CHECK( c1->getConsumers().find( con2 ) != c1->getConsumers().end() ); + CHECK( c2->getConsumers().find( con2 ) != c2->getConsumers().end() ); + } + + TEST_FIXTURE( ChannelManagerFixture, RemoveConsumer ) + { + ConsumerPtr con( new Consumer() ); + ConsumerPtr con2( new Consumer() ); + ChannelPtr c1 = manager.getChannel( id1 ); + ChannelPtr c2 = manager.getChannel( id2 ); + manager.addConsumer( con ); + manager.addConsumer( con2 ); + manager.removeConsumer( id1, con ); + + CHECK_EQUAL( 1, c1->getConsumers().size() ); + CHECK( c1->getConsumers().find( con ) == c1->getConsumers().end() ); + + manager.removeConsumer( con2 ); + CHECK_EQUAL( 0, c1->getConsumers().size() ); + CHECK_EQUAL( 1, c2->getConsumers().size() ); + CHECK( c1->getConsumers().find( con2 ) == c1->getConsumers().end() ); + CHECK( c2->getConsumers().find( con2 ) == c2->getConsumers().end() ); + CHECK( c2->getConsumers().find( con ) != c1->getConsumers().end() ); + } + + TEST_FIXTURE( ChannelManagerFixture, SetResetFilter ) + { + FilterPtr filter = Filter::create(); + ChannelPtr c1 = manager.getChannel( id1 ); + ChannelPtr c2 = manager.getChannel( id2 ); + + manager.setFilter( id1, filter ); + CHECK_EQUAL( filter, c1->getFilter() ); + + manager.setFilter( filter ); + CHECK_EQUAL( filter, c1->getFilter() ); + CHECK_EQUAL( filter, c2->getFilter() ); + + manager.resetFilter( id1 ); + CHECK( ! c1->hasFilter() ); + + manager.resetFilter(); + CHECK( ! c1->hasFilter() ); + CHECK( ! c2->hasFilter() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestConsumer.cpp b/odemx-lite/external/CppLog/src/test/src/TestConsumer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b6d67e340b4bec705a8e0336a4424bb9db5c52e --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestConsumer.cpp @@ -0,0 +1,44 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestConsumer.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for class template Consumer + * @since 0.1 + */ + +#include "global.h" +#include <string> + +SUITE( CppLogUnitTest ) +{ + struct TestConsumer: public Log::Consumer< std::string > + { + TestConsumer(): lastId( 0 ), lastRecord( "" ) {} + virtual void consume( Log::ChannelId const channelId, std::string const& record ) + { + lastId = channelId; + lastRecord = record; + } + Log::ChannelId lastId; + std::string lastRecord; + }; + + TEST( TestConsumerInterfaceCall ) + { + std::string testRecord( "test record" ); + Log::ChannelId id = 666; + Log::Channel< std::string > channel( id ); + std::shared_ptr< TestConsumer > testConsumer( new TestConsumer() ); + channel.addConsumer( testConsumer ); + channel << testRecord; + CHECK_EQUAL( channel.getId(), testConsumer->lastId ); + CHECK_EQUAL( testRecord, testConsumer->lastRecord ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestDeclareChannel.cpp b/odemx-lite/external/CppLog/src/test/src/TestDeclareChannel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b798038b4e8979a77c7c60512c5946977e31c78 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestDeclareChannel.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestDeclareChannel.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for macro CPPLOG_DECLARE_CHANNEL + * @since 0.1 + */ + +#include "global.h" +#include <string> + +static const int testChannelId = 666; +typedef unsigned long TestRecordType; + +CPPLOG_DECLARE_CHANNEL_WITH_ID( Channel, testChannel , TestRecordType, testChannelId ); + +SUITE( CppLogUnitTest ) +{ + TEST( TestDeclareChannelId ) + { + CHECK_EQUAL( testChannelId, (int)Channel::testChannel ); + } + + struct TestDeclareChannelProducer: Log::Detail::ChannelField< Channel::testChannel > + { + using Log::Detail::ChannelField< Channel::testChannel >::testChannel; + }; + struct TestDeclareChannelConsumer: Log::Consumer< TestRecordType > + { + virtual void consume( Log::ChannelId const channelId, TestRecordType const& record ) + { + lastRecord = record; + } + TestRecordType lastRecord; + }; + + TEST( TestDeclareChannelMember ) + { + TestRecordType testRecord( 42 ); + TestDeclareChannelProducer p; + std::shared_ptr< TestDeclareChannelConsumer > testConsumer( + new TestDeclareChannelConsumer() ); + + p.testChannel.reset( new Log::Channel< TestRecordType >( Channel::testChannel ) ); + p.testChannel->addConsumer( testConsumer ); + p.testChannel << testRecord; + + CHECK_EQUAL( testRecord, testConsumer->lastRecord ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestDeclareInfoType.cpp b/odemx-lite/external/CppLog/src/test/src/TestDeclareInfoType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e17b58d3dd1ac99e3edf5eb4a048a5c0885f0ad --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestDeclareInfoType.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestDeclareInfoType.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for macro CPPLOG_DECLARE_INFO_TYPE + * @since 0.1 + */ + +#include "global.h" +#include <string> + +CPPLOG_DECLARE_INFO_TYPE( PointerInfo, "pointer info", std::string* ); +CPPLOG_DECLARE_INFO_TYPE( CopyInfo, "copy info", std::string ); +CPPLOG_DECLARE_INFO_TYPE( ReferenceInfo, "reference info", std::string& ); + +SUITE( CppLogUnitTest ) +{ + TEST( TestDeclareInfoTypeStringName ) + { + CHECK_EQUAL( "pointer info", PointerInfo::getName().c_str() ); + } + + TEST( TestDeclareInfoTypePointer ) + { + std::string testString( "test string" ); + CHECK_EQUAL( &testString, PointerInfo( &testString ).value() ); + } + + TEST( TestDeclareInfoTypeCopy ) + { + std::string testString( "test string" ); + CHECK_EQUAL( "test string", CopyInfo( testString ).value()->c_str() ); + } + + TEST( TestDeclareInfoTypeReference ) + { + std::string testString( "test string" ); + CHECK_EQUAL( &testString, ReferenceInfo( testString ).value() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestDeclareInfoTypeList.cpp b/odemx-lite/external/CppLog/src/test/src/TestDeclareInfoTypeList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38551dd3ecbea9eb9aca933750a16cfc96066ac0 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestDeclareInfoTypeList.cpp @@ -0,0 +1,45 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestDeclareInfoTypeList.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for macro CPPLOG_DECLARE_INFO_TYPE_LIST + * @since 0.1 + */ + +#include "global.h" +#include <string> +#include <vector> +#include <type_traits> + +CPPLOG_DECLARE_INFO_TYPE_LIST( TestInfoTypeList, std::string, int, std::vector< bool > ); + +SUITE( CppLogUnitTest ) +{ + TEST( TestDeclareInfoTypeListTypes ) + { + bool isSame = std::is_same< + std::string, + Log::Detail::TypeOf< TestInfoTypeList, 0 >::type + >::value; + CHECK( isSame ); + + isSame = std::is_same< + int, + Log::Detail::TypeOf< TestInfoTypeList, 1 >::type + >::value; + CHECK( isSame ); + + isSame = std::is_same< + std::vector< bool >, + Log::Detail::TypeOf< TestInfoTypeList, 2 >::type + >::value; + CHECK( isSame ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestDeclareSqlColumnTypes.cpp b/odemx-lite/external/CppLog/src/test/src/TestDeclareSqlColumnTypes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..313ed3d9d9f9a9d1c9530e97863a58db891d6884 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestDeclareSqlColumnTypes.cpp @@ -0,0 +1,32 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestDeclareSqlColumnTypes.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for macro CPPLOG_DECLARE_SQL_COLUMN_TYPES + * @since 0.1 + */ + +#include "global.h" +#include <string> +#include <vector> +#include <type_traits> + +CPPLOG_DECLARE_INFO_TYPE_LIST( TestInfoTypeList, std::string, int, std::vector< bool > ); +CPPLOG_DECLARE_SQL_COLUMN_TYPES( TestInfoTypeList, testSqlTypes, "VARCHAR", "INTEGER", "BLOB" ); + +SUITE( CppLogUnitTest ) +{ + TEST( TestDeclareSqlColumnTypesValues ) + { + CHECK_EQUAL( "VARCHAR", testSqlTypes[ 0 ] ); + CHECK_EQUAL( "INTEGER", testSqlTypes[ 1 ] ); + CHECK_EQUAL( "BLOB", testSqlTypes[ 2 ] ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestEnable.cpp b/odemx-lite/external/CppLog/src/test/src/TestEnable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..759bd9a410d118190f7cac76bb756524d9231483 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestEnable.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestEnable.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for class template Enable + * @since 0.1 + */ + +#include "global.h" +#include <string> +#include <vector> +#include <type_traits> + +SUITE( CppLogUnitTest ) +{ + enum + { + id1, + id2 + }; + + TEST( TestEnableChannelFields ) + { + typedef Log::Producer< Log::Enable< id1, id2 > > TestEnableProducer; + bool inheritedField1 = std::is_base_of< + Log::Detail::ChannelField< id1 >, + TestEnableProducer + >::value; + bool inheritedField2 = std::is_base_of< + Log::Detail::ChannelField< id2 >, + TestEnableProducer + >::value; + CHECK( inheritedField1 ); + CHECK( inheritedField2 ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestFilter.cpp b/odemx-lite/external/CppLog/src/test/src/TestFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d8eea7385ef591eb347abb6b37de6ad3b16a775 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestFilter.cpp @@ -0,0 +1,62 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestFilter.cpp + * @author Ronald Kluth + * @date created at 2010/04/27 + * @brief Unit tests for class template specialization Filter< Record > + * @since 0.1 + */ + +#include "global.h" +#include <iostream> + +CPPLOG_DECLARE_INFO_TYPE( TestFilterInfo, "test filter info", std::string ) + +SUITE( CppLogUnitTest ) +{ + TEST( TestFilterRecordText ) + { + std::shared_ptr< Log::Filter<> > filter = Log::Filter<>::create(); + Log::Record rec( "text filter test" ); + filter->addRecordText() << "text filter test"; + CHECK( ! filter->pass( rec ) ); + } + + TEST( TestFilterRecordInfo ) + { + std::shared_ptr< Log::Filter<> > filter = Log::Filter<>::create(); + Log::Record rec; + rec + TestFilterInfo( "info filter test" ); + filter->add< TestFilterInfo >() << "info filter test"; + CHECK( ! filter->pass( rec ) ); + } + + TEST( TestFilterRecordMode ) + { + std::shared_ptr< Log::Filter<> > filter = Log::Filter<>::create(); + Log::Record rec( "mode filter test" ); + rec + TestFilterInfo( "mode filter test" ); + filter->addRecordText() << "mode filter test"; + filter->add< TestFilterInfo >() << "mode filter test"; + filter->passNone(); + CHECK( filter->pass( rec ) ); + filter->passAll(); + CHECK( ! filter->pass( rec ) ); + } + + TEST( TestFilterRecordReset ) + { + std::shared_ptr< Log::Filter<> > filter = Log::Filter<>::create(); + Log::Record rec; + rec + TestFilterInfo( "reset filter test" ); + filter->add< TestFilterInfo >() << "reset filter test"; + filter->resetFilter(); + CHECK( filter->pass( rec ) ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestNameScope.cpp b/odemx-lite/external/CppLog/src/test/src/TestNameScope.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e55525498b3697512f253e71139e060280ba3e1d --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestNameScope.cpp @@ -0,0 +1,56 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestNameScope.cpp + * @author Ronald Kluth + * @date created at 2009/05/17 + * @brief Unit tests for class NameScope + * @since 0.1 + */ + +#include "global.h" +#include <string> + +SUITE( CppLogUnitTest ) +{ + TEST( NameScopeDefaults ) + { + std::string defaultName = "No label given"; + char defaultSpacer = ' '; + Log::NameScope scope( defaultName, defaultSpacer ); + std::string emptyName = scope.createUniqueName( "" ); + std::string emptyName1 = scope.createUniqueName( "" ); + + CHECK_EQUAL( defaultName, emptyName ); + CHECK_EQUAL( defaultSpacer, emptyName1[ defaultName.size() ] ); + } + + TEST( NameScopeUniqueness ) + { + Log::NameScope scope; + std::set< std::string > names; + int i, iterations; + i = iterations = 10000; + while( i-- ) + { + names.insert( scope.createUniqueName( "UniqueName" ) ); + } + + CHECK_EQUAL( iterations, names.size() ); + } + + TEST( NameScopeNameCreation ) + { + Log::NameScope scope; + std::string testName = "Name Scope Test Name"; + + CHECK( scope.createUniqueName( testName ).find( testName ) != std::string::npos ); + CHECK( scope.createUniqueName( testName ).find( testName ) != std::string::npos ); + CHECK( scope.createUniqueName( testName ).find( testName ) != std::string::npos ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestNamedElement.cpp b/odemx-lite/external/CppLog/src/test/src/TestNamedElement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1db6024581a2021b293e021e1a9144dac9c4e9e --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestNamedElement.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestNamedElement.cpp + * @author Ronald Kluth + * @date created at 2009/05/18 + * @brief Unit tests for class NamedElement + * @since 0.1 + */ + +#include "global.h" +#include <string> + +SUITE( CppLogUnitTest ) +{ + TEST( NamedElementLabel ) + { + std::string label = "Label Test"; + Log::NameScope scope; + Log::NamedElement obj( scope, label ); + + CHECK_EQUAL( label , obj.getName() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestOutputDatabaseAccessor.cpp b/odemx-lite/external/CppLog/src/test/src/TestOutputDatabaseAccessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63da0d4f8bf5f2dd173d8c104204a6180be6dd6e --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestOutputDatabaseAccessor.cpp @@ -0,0 +1,176 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestOutputDatabaseAccessor.cpp + * @author Ronald Kluth + * @date created at 2010/04/28 + * @brief Unit tests for class DatabaseAccessor + * @since 0.1 + */ + +#define CPPLOG_USE_DATABASE + +#include "../../../setup.h" + +#ifndef CPPLOG_USE_ODBC +#define CPPLOG_USE_SQLITE + +#include "global.h" +#include <iostream> + +CPPLOG_DECLARE_INFO_TYPE( TestDbInfo1, "test_db_info1", std::string ) +CPPLOG_DECLARE_INFO_TYPE( TestDbInfo2, "test_db_info2", std::size_t ) +CPPLOG_DECLARE_INFO_TYPE_LIST( TestDbInfos, TestDbInfo1, TestDbInfo2 ); +CPPLOG_DECLARE_SQL_COLUMN_TYPES( TestDbInfos, testDbSqlTypes, "VARCHAR", "INTEGER" ); + +CPPLOG_DECLARE_INFO_TYPE( TestDbInfoKey, "id", std::size_t ) +CPPLOG_DECLARE_INFO_TYPE_LIST( TestStoreDataInfos, TestDbInfoKey, TestDbInfo1, TestDbInfo2 ); + +SUITE( CppLogUnitTest ) +{ + struct TestOutputDatabaseAccessorFixture + { + Log::DatabaseAccessor db; + std::string tableName; + TestOutputDatabaseAccessorFixture() + : db( "TestOutputDatabaseAccessor.db" ) + , tableName( "TestOutputDatabaseAccessor" ) + {} + + void insertRecord( Log::Record const& rec ) + { + db.insertIntoTable( tableName ) + .columnValues< TestStoreDataInfos >( rec ); + } + }; + + TEST_FIXTURE( TestOutputDatabaseAccessorFixture, CreateTable ) + { + CHECK_THROW( db.createTable( "InvalidTableColumn" ) + .column( "column with spaces", "VARCHAR" ), std::runtime_error ); + + db.createTable( tableName ) + .column( "id", "INTEGER NOT NULL" ) + .columns< TestDbInfos >( testDbSqlTypes ) + .primaryKey( "id" ); + + CHECK( db.tableExists( tableName ) ); + } + + TEST_FIXTURE( TestOutputDatabaseAccessorFixture, InsertIntoTable ) + { + bool tableExists = db.tableExists( tableName ); + CHECK( tableExists ); + + if( tableExists ) + { + Log::Record rec; + rec + TestDbInfo1( "Info1" ) + TestDbInfo2( 42 ); + + std::size_t key; + db.getMaxColumnValue( tableName, "id", key ); + db.insertIntoTable( tableName ) + .columnValue( "id", ++key ) + .columnValues< TestDbInfos >( rec ); + + CHECK_EQUAL( 1, db.getRowCount( tableName ) ); + + std::size_t keyCheck = 0; + db.getMaxColumnValue( tableName, "id", keyCheck ); + CHECK_EQUAL( key, keyCheck ); + + std::string info1Check; + db.getMaxColumnValue( tableName, TestDbInfo1NameHolder::getName().c_str(), info1Check ); + CHECK_EQUAL( "Info1", info1Check ); + + std::size_t info2Check = 0; + db.getMaxColumnValue( tableName, TestDbInfo2NameHolder::getName().c_str(), info2Check ); + CHECK_EQUAL( 42, info2Check ); + } + } + + TEST_FIXTURE( TestOutputDatabaseAccessorFixture, CreateInserter ) + { + Log::Record rec; + rec + TestDbInfo1( "Info2" ) + TestDbInfo2( 43 ); + std::size_t key = 0; + + std::auto_ptr< Log::DatabaseAccessor::SqlInserter > inserter = + db.createInserter(); + + CHECK( inserter.get() != 0 ); + + inserter->table( tableName ).column( "id" ).columns< TestDbInfos >(); + + std::ostringstream os; + os + << "INSERT INTO " + << tableName + << "(id," + << TestDbInfo1::getName().c_str() << "," + << TestDbInfo2::getName().c_str() + << ") VALUES(?,?,?)"; + + CHECK_EQUAL( os.str(), inserter->getSql() ); + + db.getMaxColumnValue( tableName, "id", key ); + inserter->value( ++key ).values< TestDbInfos >( rec ); + + CHECK_EQUAL( 3, inserter->getBindingCount() ); + + inserter->execute(); + CHECK( inserter->isExecuted() ); + } + + TEST_FIXTURE( TestOutputDatabaseAccessorFixture, CurrentDbTime ) + { + std::string currentTime = db.getCurrentDatabaseTime(); + CHECK( ! currentTime.empty() ); + } + + TEST_FIXTURE( TestOutputDatabaseAccessorFixture, StoreData ) + { + std::size_t key; + db.getMaxColumnValue( tableName, "id", key ); + + std::vector< Log::Record > buffer; + buffer.push_back( Log::Record() + TestDbInfoKey( ++key ) + + TestDbInfo1( "test store data 1" ) + TestDbInfo2( 99 ) ); + buffer.push_back( Log::Record() + TestDbInfoKey( ++key ) + + TestDbInfo1( "test store data 2" ) + TestDbInfo2( 100 ) ); + + std::size_t rowCount = db.getRowCount( tableName ); + db.storeData( buffer, + std::bind( &TestOutputDatabaseAccessorFixture::insertRecord, + this, std::placeholders::_1 ) ); + + CHECK_EQUAL( rowCount + 2, db.getRowCount( tableName ) ); + } + + TEST_FIXTURE( TestOutputDatabaseAccessorFixture, LastInsertId ) + { + db.createTable( "test_auto_inc_last_insert" ) + .column( "id", "INTEGER NOT NULL" ) + .column( "text", "VARCHAR" ) + .primaryKey( "id" ); + + db.insertIntoTable( "test_auto_inc_last_insert" ) + .columnValue( "text", "some test string" ); + + std::size_t generatedKey1 = db.getLastInsertId(); + + db.insertIntoTable( "test_auto_inc_last_insert" ) + .columnValue( "text", "some test string" ); + + std::size_t generatedKey2 = db.getLastInsertId(); + + CHECK( generatedKey1 < generatedKey2 ); + } +} + +#endif /* ! defined CPPLOG_USE_ODBC */ diff --git a/odemx-lite/external/CppLog/src/test/src/TestOutputOStreamWriter.cpp b/odemx-lite/external/CppLog/src/test/src/TestOutputOStreamWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9aeb08a30f09b67d0b330e0a03f33dd1bbc3a26 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestOutputOStreamWriter.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestOutputOStreamWriter.cpp + * @author Ronald Kluth + * @date created at 2010/04/28 + * @brief Unit tests for class template OStreamWriter + * @since 0.1 + */ + +#include "global.h" + +SUITE( CppLogUnitTest ) +{ + typedef Log::OStreamWriter< Infos > OStreamWriterType; + typedef std::shared_ptr< OStreamWriterType > OStreamWriterPtr; + + TEST( TestOStreamWriterConsume ) + { + std::ostringstream os; + OStreamWriterPtr osWriter = OStreamWriterType::create( os ); + + Point3d p3d = { 7, 8, 9 }; + osWriter->consume( 0, + Log::Record( "test_ostream_writer_consume" ) + + StringInfo( "test_string_info" ) + + PointInfo( p3d ) ); + + CHECK( find( os.str(), "test_ostream_writer_consume" ) ); + CHECK( find( os.str(), "test_string_info=test_string_info" ) ); + CHECK( find( os.str(), "test_point_info=(7 8 9)" ) ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestOutputXmlFileWriter.cpp b/odemx-lite/external/CppLog/src/test/src/TestOutputXmlFileWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0df8bdeb86c5e0a5c166bb64a0432e86cdedaf4 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestOutputXmlFileWriter.cpp @@ -0,0 +1,100 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestOutputXmlFileWriter.cpp + * @author Ronald Kluth + * @date created at 2010/04/28 + * @brief Unit tests for class template XmlFileWriter + * @since 0.1 + */ + +#include "global.h" +#include <Poco/File.h> + +SUITE( CppLogUnitTest ) +{ + struct TestXmlFileWriterFixture + { + typedef Log::XmlFileWriter< Infos > XmlFileWriterType; + typedef std::shared_ptr< XmlFileWriterType > XmlFileWriterPtr; + std::string fileNameBase; + XmlFileWriterPtr xmlWriter; + TestXmlFileWriterFixture() + : fileNameBase( "TestXmlFileWriter" ) + , xmlWriter() + {} + }; + + TEST_FIXTURE( TestXmlFileWriterFixture, NewFileAfterConstruction ) + { + // a new file should have been opened during construction + xmlWriter = XmlFileWriterType::create( fileNameBase, 3 ); + Poco::File file( fileNameBase + "_0.xml" ); + CHECK( file.exists() ); + } + + TEST_FIXTURE( TestXmlFileWriterFixture, Consume ) + { + xmlWriter = XmlFileWriterType::create( + fileNameBase, 3, "test_xml_file_writer", 4 ); + + Point3d p3d = { 1, 2, 3 }; + xmlWriter->consume( 0, + Log::Record( "test_xml_file_writer_consume" ) + + StringInfo( "test_string_info" ) + PointInfo( p3d ) ); + xmlWriter.reset(); // should destroy the writer and close the file + + Poco::File file( fileNameBase + "_0.xml" ); + CHECK( file.exists() ); + + std::ifstream is( (fileNameBase + "_0.xml").c_str(), std::ifstream::in ); + std::string line; + std::getline( is, line ); + CHECK( find( line, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ) ); + + std::getline( is, line ); + CHECK( find( line, "<test_xml_file_writer>" ) ); + + std::getline( is, line ); + CHECK( find( line, " <record>" ) ); + + std::getline( is, line ); + CHECK( find( line, " <text>test_xml_file_writer_consume</text>" ) ); + + std::getline( is, line ); + CHECK( find( line, " <test_string_info>test_string_info</test_string_info>" ) ); + + std::getline( is, line ); + CHECK( find( line, " <test_point_info>(1 2 3)</test_point_info>" ) ); + + std::getline( is, line ); + CHECK( find( line, " </record>" ) ); + + std::getline( is, line ); + CHECK( find( line, "</test_xml_file_writer>" ) ); + } + + TEST_FIXTURE( TestXmlFileWriterFixture, LimitReachedStartNewFile ) + { + xmlWriter = XmlFileWriterType::create( + fileNameBase, 3, "test_xml_file_writer", 4 ); + + int i = 4; + while( i-- ) + { + Point3d p3d = { 1, 2, 3 }; + xmlWriter->consume( 0, + Log::Record( "test_xml_file_writer_consume" ) + + StringInfo( "test_string_info" ) + PointInfo( p3d ) ); + } + xmlWriter.reset(); // should destroy the writer and close the file + + Poco::File file( fileNameBase + "_1.xml" ); + CHECK( file.exists() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestOutputXmlStreamWriter.cpp b/odemx-lite/external/CppLog/src/test/src/TestOutputXmlStreamWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27c72920c4c1a4969c367726e1aac480c2ce8f5d --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestOutputXmlStreamWriter.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestOutputXmlStreamWriter.cpp + * @author Ronald Kluth + * @date created at 2010/04/28 + * @brief Unit tests for class template XmlStreamWriter + * @since 0.1 + */ + +#include "global.h" + +SUITE( CppLogUnitTest ) +{ + typedef Log::XmlStreamWriter< Infos > XmlStreamWriterType; + typedef std::shared_ptr< XmlStreamWriterType > XmlStreamWriterPtr; + + TEST( TestXmlStreamWriterConsume ) + { + std::ostringstream os; + XmlStreamWriterPtr xmlWriter = XmlStreamWriterType::create( os, 2 ); + + Point3d p3d = { 4, 5, 6 }; + xmlWriter->consume( 0, + Log::Record( "test_xml_stream_writer_consume" ) + + StringInfo( "test_string_info" ) + + PointInfo( p3d ) ); + + CHECK( find( os.str(), " <record>" ) ); + CHECK( find( os.str(), " <text>test_xml_stream_writer_consume</text>" ) ); + CHECK( find( os.str(), " <test_string_info>test_string_info</test_string_info>" ) ); + CHECK( find( os.str(), " <test_point_info>(4 5 6)</test_point_info>" ) ); + CHECK( find( os.str(), " </record>" ) ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestOutputXmlWriter.cpp b/odemx-lite/external/CppLog/src/test/src/TestOutputXmlWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d63b5d81b98b990bfeb5012bb268f561d357fb6 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestOutputXmlWriter.cpp @@ -0,0 +1,70 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestOutputXmlWriter.cpp + * @author Ronald Kluth + * @date created at 2010/04/28 + * @brief Unit tests for class XmlWriter + * @since 0.1 + */ + +#include "global.h" +#include <string> + +SUITE( CppLogUnitTest ) +{ + TEST( TestXmlWriterStartElement ) + { + std::ostringstream os; + Log::XmlWriter::startElement( os, 4, "test_start_element" ); + CHECK_EQUAL( " <test_start_element>", os.str() ); + } + + TEST( TestXmlWriterCloseElement ) + { + std::ostringstream os; + Log::XmlWriter::closeElement( os, 4, "test_close_element" ); + CHECK_EQUAL( " </test_close_element>\n", os.str() ); + } + + TEST( TestXmlWriterEmptyElement ) + { + std::ostringstream os; + Log::XmlWriter::emptyElement( os, 4, "test_empty_element" ); + CHECK_EQUAL( " <test_empty_element/>\n", os.str() ); + } + + TEST( TestXmlWriterWriteElement ) + { + std::ostringstream os; + Log::XmlWriter::writeElement( os, 4, "test_write_element", 999 ); + CHECK_EQUAL( " <test_write_element>999</test_write_element>\n", os.str() ); + } + + TEST( TestXmlWriterWriteHeader ) + { + std::ostringstream os; + Log::XmlWriter::writeHeader( os ); + CHECK_EQUAL( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", os.str() ); + } + + struct DummyXmlWriter: Log::XmlWriter + { + using Log::XmlWriter::StreamInfoElements; + }; + + TEST( TestXmlWriterStreamInfoElements ) + { + std::ostringstream os; + DummyXmlWriter::StreamInfoElements writer( os, 2 ); + writer( "test_stream_info_elements_value", 111, true ); + writer( "test_stream_info_elements_empty", 111, false ); + CHECK_EQUAL( " <test_stream_info_elements_value>111</test_stream_info_elements_value>\n" + " <test_stream_info_elements_empty/>\n", os.str() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestProducer.cpp b/odemx-lite/external/CppLog/src/test/src/TestProducer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4b7775de0b277c46294aaaefada413a1a0608d7 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestProducer.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestProducer.cpp + * @author Ronald Kluth + * @date created at 2009/05/17 + * @brief Unit tests for class template DataProducer + * @since 0.1 + */ + +#include "global.h" +#include <string> + +CPPLOG_DECLARE_CHANNEL_WITH_ID( test, channel_one, int, 0 ); +CPPLOG_DECLARE_CHANNEL_WITH_ID( test, channel_two, int, 1 ); + +typedef Log::Producer< Log::Enable< test::channel_one, test::channel_two > > ProducerType; + +SUITE( CppLogUnitTest ) +{ + struct Producer: ProducerType + { + typedef std::shared_ptr< Log::Channel< int > > ChannelPtr; + + Producer( Log::NameScope& scope, std::string const& name ) + : ProducerType( scope, name ) + {} + Producer( Log::ChannelManager< int >& scope, std::string const& name ) + : ProducerType( scope, name ) + {} + ChannelPtr getChannelOne() + { + return channel_one; + } + ChannelPtr getChannelTwo() + { + return channel_two; + } + }; + + TEST( ProducerName ) + { + Log::NameScope scope; + Log::ChannelManager< int > manager; + std::string name( "Test Producer" ); + Producer producer1( scope, name ); + Producer producer2( manager, name ); + CHECK_EQUAL( name, producer1.getName() ); + CHECK_EQUAL( name, producer2.getName() ); + } + + TEST( ProducerChannelMemberInit ) + { + Log::ChannelManager< int > manager; + Producer producer( manager, "Test Producer" ); + CHECK( producer.getChannelOne() ); + CHECK( producer.getChannelTwo() ); + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/TestRecord.cpp b/odemx-lite/external/CppLog/src/test/src/TestRecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5ef56bb434ebc402726dc0f80f7cd4824d561dc --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/TestRecord.cpp @@ -0,0 +1,52 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file TestRecord.cpp + * @author Ronald Kluth + * @date created at 2009/05/29 + * @brief Unit tests for class Record + * @since 0.1 + */ + +#include "global.h" +#include <string> +#include <iostream> + +CPPLOG_DECLARE_INFO_TYPE( TestInfo, "test info", char ); + +SUITE( CppLogUnitTest ) +{ + TEST( RecordText ) + { + Log::StringLiteral message = "Log record test message"; + Log::Record rec( message ); + CHECK_EQUAL( message, rec.getText() ); + } + + TEST( RecordInfo ) + { + Log::Record rec; + Log::StringLiteral f = __FILE__; + int l = __LINE__; + Log::StringLiteral s = "TestRecordInfo"; + + rec.file( f ).line( l ).scope( s ); + CHECK( rec.get< Log::FileInfo >() ); + CHECK( rec.get< Log::LineInfo >() ); + CHECK( rec.get< Log::ScopeInfo >() ); + CHECK_EQUAL( f, *rec.get< Log::FileInfo >() ); + CHECK_EQUAL( l, *rec.get< Log::LineInfo >() ); + CHECK_EQUAL( s, *rec.get< Log::ScopeInfo >() ); + CHECK_EQUAL( (void*)0, rec.get< TestInfo >() ); +/* + char c = 'X'; + rec + TestInfo( c ); + CHECK( rec.get< TestInfo >() ); + CHECK_EQUAL( c, *rec.get< TestInfo >() );*/ + } +} diff --git a/odemx-lite/external/CppLog/src/test/src/global.cpp b/odemx-lite/external/CppLog/src/test/src/global.cpp new file mode 100644 index 0000000000000000000000000000000000000000..089d1702733d0ef3e6bf6b827a75a305bc299dff --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/global.cpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file global.cpp + * @date created at 2010/04/28 + * @author Ronald Kluth + * @brief Implementation of global components used for testing + */ + +#include "global.h" + +namespace SuiteCppLogUnitTest { + +std::ostream& operator<<( std::ostream& os, Point3d const& p ) +{ + os << "(" << p.x << " " << p.y << " " << p.z << ")"; + return os; +} + +bool find( std::string const& str, std::string const& seq ) +{ + std::size_t found = str.find( seq ); + return found != std::string::npos; +} + +} diff --git a/odemx-lite/external/CppLog/src/test/src/global.h b/odemx-lite/external/CppLog/src/test/src/global.h new file mode 100644 index 0000000000000000000000000000000000000000..90d78d50eeddf576b38bf154b674e6701071d4d3 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/global.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file global.h + * @date created at 2010/04/28 + * @author Ronald Kluth + * @brief Declaration of global components used for testing + */ + +#ifndef CPPLOGTEST_GLOBAL_INCLUDED +#define CPPLOGTEST_GLOBAL_INCLUDED + +#include <UnitTest++.h> +#include <CppLog.h> + +namespace SuiteCppLogUnitTest { + +struct Point3d +{ + float x, y, z; +}; + +extern std::ostream& operator<<( std::ostream& os, Point3d const& p ); + +CPPLOG_DECLARE_INFO_TYPE( StringInfo, "test_string_info", std::string ); +CPPLOG_DECLARE_INFO_TYPE( PointInfo, "test_point_info", Point3d ); +CPPLOG_DECLARE_INFO_TYPE_LIST( Infos, StringInfo, PointInfo ); + +extern bool find( std::string const& str, std::string const& seq ); + +} // namespace CppLogUnitTest + +#endif /* CPPLOGTEST_GLOBAL_INCLUDED */ diff --git a/odemx-lite/external/CppLog/src/test/src/main.cpp b/odemx-lite/external/CppLog/src/test/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..904e2f68e933d990f75ab441a6e937254a342620 --- /dev/null +++ b/odemx-lite/external/CppLog/src/test/src/main.cpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2010 Ronald Kluth +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** + * @file global.cpp + * @date created at 2010/04/28 + * @author Ronald Kluth + * @brief Implementation of global components used for testing + */ + +#include <UnitTest++.h> + +/** + * @brief This is the main function for the test runner application + * + * The function automatically runs all registered test suites. + * and returns the value of UnitTest::RunAllTests(), which states + * how many tests have failed during execution. + */ +int main() +{ + return UnitTest::RunAllTests(); +} diff --git a/odemx-lite/include/odemx/base/Comparators.h b/odemx-lite/include/odemx/base/Comparators.h new file mode 100644 index 0000000000000000000000000000000000000000..b1d7842881de89c891c96a1a2a72aac42d6edda2 --- /dev/null +++ b/odemx-lite/include/odemx/base/Comparators.h @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Comparators.h + * @author Ronald Kluth + * @date created at 2009/02/23 + * @brief Declaration of odemx::base::DefaultCmp and odemx::base::QPriorityCmp + * @sa Comparators.cpp + * @since 3.0 + */ + +#ifndef ODEMX_BASE_COMPARATORS_INCLUDED +#define ODEMX_BASE_COMPARATORS_INCLUDED + +namespace odemx { +namespace base { + +// forward declarations +class Sched; +class Process; + +/** \struct DefaultCmp + + \author Ronald Kluth + + \brief DefaultCmp is used for ordering objects in std::list<> + + \sa ListInSort, QPriorityCmp +*/ +struct DefaultCmp +{ + bool operator()( const Sched* s1, const Sched* s2 ) const; +}; + +/** + \var defCmp + \author Ronald Kluth + \brief defCmp is a callable object of type DefaultCmp. + */ +extern DefaultCmp defCmp; + +/** \struct QPriorityCmp + + \author Ronald Kluth + + \brief QPriorityCmp is used for ordering objects in std::list<> + + \sa ListInSort, DefaultCmp +*/ +struct QPriorityCmp +{ + bool operator()( const Process* p1, const Process* p2 ) const; +}; + + +/** + \var qPrioCmp + \author Ronald Kluth + \brief qPrioCmp is a callable object of type QPriorityCmp. + */ +extern QPriorityCmp qPrioCmp; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_COMPARATORS_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/Continuous.h b/odemx-lite/include/odemx/base/Continuous.h new file mode 100644 index 0000000000000000000000000000000000000000..512f9afbaff519279f5444420b4601d01348e069 --- /dev/null +++ b/odemx-lite/include/odemx/base/Continuous.h @@ -0,0 +1,459 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file base/Continuous.h + * @author Ralf Gerstenberger + * @date created at 2003/06/15 + * @brief Declaration of odemx::base::Continuous, its observer, and odemx::base::ContuTrace + * @sa Continuous.cpp + * @since 1.0 + */ + +#ifndef ODEMX_BASE_CONTINUOUS_INCLUDED +#define ODEMX_BASE_CONTINUOUS_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/Process.h> +#include <odemx/base/TypeDefs.h> + +#include <string> +#include <vector> +#include <list> + +namespace odemx { +namespace base { + +// forward declaration +class ContinuousObserver; + +/** \class Continuous + + \ingroup base + + \author Ralf Gerstenberger + + \brief Time continuous process + + \note %Continuous supports Observation. + \note %Continuous supports Trace. + + \sa Process + + %Continuous is a base class for all user defined time continuous + processes. It provides functionality of Process and introduces + the possibility to define time continuous processes. A user has + to implement the derivatives() function to define the time + continuous state changes. The function integrate() computes + the time continuous state changes. + + \par Example: + \include continuousProcesses.cpp + + \since 1.0 +*/ +class Continuous +: public Process // is DataProducer, etc. +, public data::Observable< ContinuousObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to the Simulation object + \param l + label of this object + \param d + number of state variables used in derivatives() + \param o + initial observer + */ + Continuous( Simulation& sim, const data::Label& label, int dimension, + ContinuousObserver* o = 0 ); + + /// Destruction + virtual ~Continuous(); + + /** + \brief Interrupt + + If a %Continuous process is interrupted inside integrate() + the computation is not synchronised to the time of the + interrupt. There might be an error depending on the step length. + This can be prevented if the process that caused the + interrupt is registered as a peer to the continuous process. + + \sa Process::interrupt + */ + virtual void interrupt(); + + /** + \brief Get number of state variables + + %getDimension() returns the number of state variables specified + in the constructor. No more than the specified state variables + may me used in derivatives(). The state variables are stored in + the STL vector state. + */ + unsigned int getDimension() const; + + /** + \brief Set minimum and maximum step length + + \param min + minimum step length + \param max + maximum step length + + The integrate() function computes state changes step by step. + The step length used is variable depending on numerical errors, + state events and registered peer processes. With %setStepLength() + the user can choose boundaries for the step length according to + the needed accuracy. + + \sa integrate(), addPeer() + + */ + void setStepLength( double min, double max ); + + /** + \brief Get current step length + + The integrate() function computes state changes step by step. + The step length used is variable depending on numerical errors, + state events and registered peer processes. %getStepLength() + returns the current step length. + + \sa integrate() + */ + double getStepLength() const; + + /** + \brief Set errorlimit + + \param type + error type: 1 for relative error; 0 for absolute error + \param limit + error limit + + The integrate() function computes state changes step by step. + The step length used does depend on the numerical error during + computation. With %setErrorlimit() the user can set the highest + acceptable error. If the actual error is higher the step length + is reduced. \n + The limit can be set absolute or relative. In the second case the + limit is interpreted relative to the actual state values. + + \sa integrate() + + */ + void setErrorlimit( int type, double limit ); + + /** + \brief Add a partner process + + \param p + pointer to Process object + + The integrate() function computes state changes step by step. The + next state value is computed in advance to the time consumption. + If another process is accessing the state variables during the + time consumption it receives wrong values. The step length however + is variable and can be changed to synchronise computation with + partner Processes. The function %addPeer() is used to register + partner Processes for synchronisation. + + \note + A peer must have a higher priority than its continuous partner + to interact properly. To support this a continuous process + reduces its priority by one inside integrate(). A peer has to + ensure that its priority is at least as high as the priority of + the continuous process. + + \sa integrate(), delPeer() + */ + void addPeer( Process* newPeer ); + + /** + \brief Remove a peer + + \param p + pointer to Process object + + Removes a registered partner process. + + \sa addPeer() + */ + void delPeer( Process* newPeer ); + + /** + \brief State variables + + The \c state variables used during time continuous state changes + are stored in this STL vector. A process which is accessing + this variables directly should be registered with addPeer(). + + \sa integrate(), derivatives(), addPeer() + */ + std::vector< double > state; + + /** + \brief Rate variables + + The STL vector \c rate is used for the computation of time continuous + state changes. The state variables are not changed directly. In + derivatives() the user sets the rate by witch each state variable + is changed. + + \sa integrate(), derivatives() + */ + std::vector< double > rate; + + /** + \brief Error vector + + The step by step computation of time continuous state changes + introduces an inherent error. This error is computed for every state + variable independently. \c error_vector is used to store the error + values. The virtual function errorNorm() is called to compute a + single error value from this vector which is stored in \c error_value. + + \sa integrate(), errorNorm(), error_value + */ + std::vector< double > error_vector; + + /** + \brief Error + + The step by step computation of time continuous state changes + introduces an inherent error. This error is computed for every state + variable independently. The function errorNorm() is used to compute + a single error value from the vector of error values which is stored + in \c error_value. + + \sa integrate(), errorNorm() + */ + double error_value; + +protected: + /** + \brief User defined process behaviour + + This function is implemented by the user to define the process + behaviour. + + \sa Process::main() + */ + virtual int main() = 0; + + /** + \brief User defined continuous behaviour + + \param t + time + + The user has to implement the function %derivatives() to define + the time continuous state changes. This is done indirectly by + setting the rate by witch each state variable changes. The function + is called by integrate() several times for each step. + + \dontinclude continuousExample.cpp + \par Example Oscillator + The %derivatives() function describes a simple sin/cos oscillator. + The two rate variables depend only on the two state variables: + \skipline virtual void derivatives (double t) { + \until } + + \par Example FreeFall + This %derivatives() function uses the provided parameter \p t + to include the current time in the computation: + \skipline virtual void derivatives (double t) { + \until } + + \note + If the time is required for the computation of the rates the + prameter \p t has to be used instead of getCurrentTime(). + + \sa integrate(), rate, state + */ + virtual void derivatives( double t ) = 0; + + /** + \brief Computation of time continuous state changes + + \param timeEvent + time limit for integration (0->infinite) + \param stateEvent + state event that stops integration by returning true (member call-back-function) + \return 0 if timeEvent hit; 1 if stateEvent hit; + 2 if interrupted + + The function %integrate() computes time continuous state changes + using the Runge-Kutta algorithm. The computation is stopped when + the time \p timeEvent is reached, the state event occurred or + the interrupt() function was called. \n + The computation is done step by step with a varying step length. The + actual step length depends on computation errors, registered peers + and the stop time (\p timeEvent). The user can set boundaries to + the step length with the function setStepLength(). The default + values used by integrate are 0.01 and 0.1 for minimum and maximum. + \n + The step by step computation of time continuous processes introduces + an inherent error. integrate() observes the computational errors for + each state variable. The function errorNorm() is called to compute + a single value from all error values. The user can use the function + setErrorlimit() to specify the largest acceptable error. If the single + value computed by errorNorm() exceeds the acceptable error %integrate() + tries to reduce the step length. This fails if the resulting step + length would be smaller than the minimum step length set with setStepLength(). + The default error limit is an absolute error of 0.1. + \n + If during the computation a state event occurred, integrate() starts + a binary search to find the exact time of the event. The minimum + step length set by setStepLength() defines the accuracy of this + search. + \n + %integrate() synchronises computation with partner processes. A process + is registered as a partner with the function addPeer(). + + \sa derivatives(), setStepLength(), setErrorlimit(), errorNorm(), addPeer() and + state + */ + int integrate( SimTime timeEvent, Condition stateEvent = 0 ); + +protected: + // Dimension + int dimension; // highest index + + // integrations steps + double stepLength; + double maxStepLength, minStepLength; + + // integration time + double time; + + // solver error handling + int relative; + double errorLimit; + + /** + \brief Compute error + + \return single error value + + This function is called to compute a single error value + from the error_vector. The default implementation returns + the largest error(). A user can overwrite this function to + use another error norm. + + \sa error, error_value and integrate() + */ + virtual double errorNorm(); + + // solver + int stopped; + + std::vector<double> initial_state; + std::vector<double> slope_1; + std::vector<double> slope_2; + std::vector<double> slope_3; + + int reduce(); + void binSearch(); + virtual void takeAStep(double h); + + // stop condition + bool stopIntegrate(); + SimTime stopTime; + Condition stopCond; + + // peers + ProcessList peers; +}; + +/** \interface ContinuousObserver + + \author Ralf Gerstenberger + + \brief Observer for Continuous specific events + + \sa Continuous + + \since 1.0 +*/ +class ContinuousObserver: + public ProcessObserver +{ +public: +// virtual void onCreate( Continuous* sender ) {} ///< Construction + + virtual void onAddPeer( Continuous* sender, Process* peer ) {} ///< Add peer + virtual void onRemovePeer( Continuous* sender, Process* peer ) {} ///< Remove peer + + virtual void onBeginIntegrate( Continuous* sender ) {} ///< Begin integrate + virtual void onEndIntegrate( Continuous* sender, int result ) {} ///< End integrate + + virtual void onNewValidState( Continuous* sender ) {} ///< New valid state +}; + +/** \class ContuTrace + + \author Ralf Gerstenberger + + \brief Trace for Continuous state changes + + \sa Continuous ContinuousObserver + + ContuTrace logs the state changes of a Continuous object + into a text file. The text file is automatically opened + and closed. + + \since 1.0 +*/ +class ContuTrace +: public ContinuousObserver +{ +public: + /// Construction + ContuTrace( Continuous* contu = 0, const std::string& fileName = "" ); + /// Destruction + virtual ~ContuTrace(); + + /// Follow state changes + virtual void onNewValidState( Continuous* sender ); + +private: + // Implementation + std::ostream* out; + bool firstTime; + + void openFile( const std::string& fileName ); +}; + +} } // namespace odemx::base + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_BASE_CONTINUOUS_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/DefaultSimulation.h b/odemx-lite/include/odemx/base/DefaultSimulation.h new file mode 100644 index 0000000000000000000000000000000000000000..02fad318a8817224881c760cd8b30da632aae4da --- /dev/null +++ b/odemx-lite/include/odemx/base/DefaultSimulation.h @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file DefaultSimulation.h + * @author Ronald Kluth + * @date created at 2009/02/07 + * @brief Declaration of class DefaultSimulation and getDefaultSimulation + * @sa DefaultSimulation.cpp, Simulation.h, Simulation.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DEFAULTSIMULATION_INCLUDED +#define ODEMX_DEFAULTSIMULATION_INCLUDED + +#include <odemx/base/Simulation.h> + +namespace odemx { + +/** + @brief Get the DefaultSimulation + @return Reference to the DefaultSimulation object + + The first time getDefaultSimulation() is called, an + object of type DefaultSimulation is created and returned. + All following calls to getDefaultSimulation() also return + this object. + + @note The reference returned by this function refers to a static object. + DefaultSimulation access is basically implemented like a Meyers singleton. + + @see DefaultSimulation +*/ +extern base::Simulation& getDefaultSimulation(); + +namespace base { + +/** \class DefaultSimulation + + \author Ralf Gerstenberger + + \brief A default implementation of Simulation provided for convenience. + + The %DefaultSimulation is provided for convenience. You can + use this simulation if you don't want to define your own. Use + getDefaultSimulation() to get a pointer to a %DefaultSimulation + object. Instead of \p init(), the \p main function of your simulation + program will be required to initialize all necessary objects for + the start of the simulation. + + \since 1.0 +*/ +class DefaultSimulation +: public Simulation +{ +private: + + friend Simulation& odemx::getDefaultSimulation(); + + /** + \brief Construction + + Use odemx::getDefaultSimulation() to get an object of %DefaultSimulation. + + \sa odemx::getDefaultSimulation() + */ + DefaultSimulation(); + + /// private Destructor to prevent delete calls + ~DefaultSimulation(); + +protected: + virtual void initSimulation(); +}; + +} } // namespace odemx::base + +#endif /*ODEMX_DEFAULTSIMULATION_INCLUDED*/ diff --git a/odemx-lite/include/odemx/base/Event.h b/odemx-lite/include/odemx/base/Event.h new file mode 100644 index 0000000000000000000000000000000000000000..c47eb81ac9268e2a0a7bacd509f0b52a95786b3c --- /dev/null +++ b/odemx-lite/include/odemx/base/Event.h @@ -0,0 +1,343 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Event.h + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Declaration of odemx::base::Event and observer + * @sa Event.cpp + * @since 2.0 + */ + +#ifndef ODEMX_BASE_EVENT_INCLUDED +#define ODEMX_BASE_EVENT_INCLUDED + +#include <odemx/base/Sched.h> +#include <odemx/data/Observable.h> +#include <odemx/util/attributes.h> + +namespace odemx { +namespace base { + +// forward declaration +class Simulation; +class EventObserver; + +/** \class Event + + \ingroup base + + \author Ronald Kluth + + \brief %Event is the base class for all user-defined events in a model. + + \note %Event supports Observation. + \note %Event supports Trace. + + \sa Process, Simulation + + %Event is the base class for all user defined events in a model. Events, + unlike processes do not have a life cycle consisting of a chain of actions. + An event is a single action that changes the state of the system model. + It can, however be executed more than once. A user + creates a derived class for every different type of event of their model. + In their own classes users have to provide the event action by implementing + the eventAction() method. The event action is executed according to an + execution schedule (ExecutionList) at a certain point in simulation time. + If multiple scheduled objects share the same execution time, the order of + execution is defined by the way the processes and/or events have been + scheduled. These objects can be scheduled with respect to their priority + First-In-First-Out or Last-In-First-Out at a point in time. + + \since 2.0 +*/ +class Event +: public Sched // is DataProducer, etc. +, public data::Observable< EventObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param sim + Reference to the simulation object + \param label + Label of this object + \param obs + Initial observer + */ + Event( Simulation& sim, const data::Label& label, EventObserver* obs = 0 ); + + /// Destruction + virtual ~Event(); + + + /** + \name Event Scheduling + + These functions are used to schedule a simulation event + in simulation time. Events and processes are kept in one + schedule and follow the same scheduling rules. + + @{ + */ + /** + \brief Trigger the event at current simulation time + + This function schedules the event at the current time before + all other processes and events with the same priority (LIFO). Unlike + high-priority processes, scheduling high-priority events at + SimTime now will not suspend the execution of the current process + - the process can either finish or reschedule itself, after which + the event will then be triggered. + */ + void schedule(); + + /** + \brief Trigger the event in (relative) time \p t + \param t + delay for activation + + This function schedules the event at the simtime \c now + \p t + before all other processes with the same priority (LIFO). If + \p t is 0 this function is equal to schedule(). + + \sa schedule() + */ + void scheduleIn( SimTime t ); + + /** + \brief Trigger the event at (absolute) time \p t + \param t + time for activation + + This function schedules the event at the simtime \p t + before all other processes with the same priority (LIFO). If + \p t is \c now this function is equal to schedule(). + + \sa schedule() + */ + void scheduleAt( SimTime t ); // schedule at absolute simulation time t + + /** + \brief Trigger the event at current simulation time (FIFO) + + This function schedules the event at the current time + after all other scheduled objects with the same priority. + */ + void scheduleAppend(); + + /** + \brief Trigger the event in (relative) time \p t (FIFO) + + This function schedules the event at the time \c now + \p t + after all other scheduled objects with the same priority. If \p t + is 0 this function is equal to scheduleAppend(). + + \sa scheduleAppend() + */ + void scheduleAppendIn( SimTime t ); + + /** + \brief Trigger the event at (absolute) time \p t (FIFO) + + This function schedules the event at simtime \p t + after all other scheduled objects with the same priority. If \p t + is \c now this function is equal to scheduleAppend(). + + \sa scheduleAppend() + */ + void scheduleAppendAt( SimTime t ); + + /** + \brief Remove the event from the execution list + + This function finds this event in the execution list + and deletes the entry. + */ + void removeFromSchedule(); + //@} + + /** + \name Priority + + These functions can be used to adjust the priority of the event. + A priority change causes an update of the execution list as scheduled + objects may switch positions. By default, events have the same + priority as processes. + + @{ + */ + /** + \brief Get priority + \return + event priority + + This function returns the current event priority. + */ + virtual Priority getPriority() const; + + /** + \brief Set new priority + \return + previous event priority + + This function changes the event priority. The position + in the execution schedule and in queues is affected by + priority changes. + */ + virtual Priority setPriority( Priority newPriority ); + //@} + + /** + \name Execution Time + + @{ + */ + /** + \brief Get execution time + \return + execution time; 0 if the event is not scheduled + + This function returns the execution time of the event. + An event is scheduled to be triggered at its execution time. + */ + SimTime getExecutionTime() const; + //@} + + /** + \name Current System State + + @{ + */ + /** + \brief Get current simulation time + \deprecated substituted by Sched::getTime () + \return + current simulation time + + This function returns the current simulation time. + */ + DEPRECATED(SimTime getCurrentTime()); + //@} + + /** \cond PLEASE_DELETE_THIS_AND_CLOSE_#41 + \brief Get pointer to Trace + \return + pointer to Trace object + */ + //virtual data::Trace* getTrace() const; + // \endcond + +protected: + /** + \brief User defined event action + + This function must be implemented by the user to define the + action the event triggers. It is executed by ODEMx when the event + becomes the first, i.e. current, element in the schedule. + If a scheduling function is called (directly or indirectly, + on itself or another process/event) the eventAction() function will still + finish, unlike processes, which would then be suspended. + The sequence in which different processes and events are executed + is determined by the execution schedule. + + \sa Process Scheduling + */ + virtual void eventAction() = 0; + +private: + + friend class ExecutionList; + + /** + \brief Set execution time + \return + previous execution time + + This function is used by the library. Don't + call it directly! Use the scheduling functions + instead. + */ + SimTime setExecutionTime( SimTime time ); + + friend class Simulation; + + /** + \brief Execution of this event + + This function is used by the library. Don't + call it directly! The execution is managed + by the scheduling mechanism. + */ + void execute(); + +private: + + SimTime executionTime_; ///< simulation time of next event execution + Priority priority_; ///< priority for scheduling + + /** + \brief Get currently running Sched object or simulation + \return + pointer to simulation or current Sched object + */ + const data::Label& getPartner(); +}; + +/** \interface EventObserver + + \author Ronald Kluth + + \brief Observer for Event-specific calls. + + \sa Event + + \since 2.0 +*/ +class EventObserver +{ +public: + virtual ~EventObserver() {} + + virtual void onCreate( Event* sender ) {} ///< Construction + + /// Activation (LIFO) + virtual void onSchedule( Event* sender ) {} ///< Immediate triggering + virtual void onScheduleAt( Event* sender, SimTime t ) {} ///< Trigger at + virtual void onScheduleIn( Event* sender, SimTime t ) {} ///< Trigger in + + /// Activation (FIFO) + virtual void onScheduleAppend( Event* sender ) {} ///< Hold Triggering + virtual void onScheduleAppendAt( Event* sender, SimTime t ) {} ///< Hold triggering at + virtual void onScheduleAppendIn( Event* sender, SimTime t ) {} ///< Hold triggering in + + /// Removal / Execution + virtual void onRemoveFromSchedule( Event* sender ) {} ///< Event de-scheduled + virtual void onExecuteEvent( Event* sender ) {} ///< Event executed + + /// Event priority change + virtual void onChangePriority( Event* sender, Priority oldPriority, Priority newPriority ) {} + /// Event execution time change + virtual void onChangeExecutionTime( Event* sender, SimTime oldExecutionTime, SimTime newExecutionTime ) {} +}; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_EVENT_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/ExecutionList.h b/odemx-lite/include/odemx/base/ExecutionList.h new file mode 100644 index 0000000000000000000000000000000000000000..7863210346b61659fa49ac0786fc0e74ded3d913 --- /dev/null +++ b/odemx-lite/include/odemx/base/ExecutionList.h @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ExecutionList.h + * @author Ralf Gerstenberger + * @date created at 2002/01/23 + * @brief Declaration of odemx::base::ExecutionList + * @sa ExecutionList.cpp + * @since 1.0 + */ + +#ifndef ODEMX_EXECUTIONLIST_INCLUDED +#define ODEMX_EXECUTIONLIST_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/base/TypeDefs.h> +#include <odemx/data/Label.h> +#include <odemx/data/Producer.h> +#include <odemx/data/Observable.h> +#include <CppLog/Channel.h> + +namespace odemx { + +namespace data { class SimRecord; } + +namespace base { + +// forward declarations +class Scheduler; +class Simulation; + +typedef std::shared_ptr< Log::Channel< data::SimRecord > > ChannelPtr; + +/** \class ExecutionList + + \ingroup base + + \author Ralf Gerstenberger + + \brief ExecutionList implements an execution schedule for Sched objects. + + \note ExecutionList supports Observation. + + ExecutionList is used to manage the Sched execution order. A Sched object + is scheduled at a given time considering its priority and a FIFO- or LIFO- + strategy, or in relation to an already scheduled object. + + \since 1.0 +*/ +class ExecutionList +: public data::Producer +{ +public: + /// Construction with Simulation + ExecutionList( Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~ExecutionList(); + + /** + \brief Print the schedule + + This function prints a simple representation of the + execution list to stdout. + */ + void logToChannel( const ChannelPtr channel ) const; + + /** + \name Sched Management + + @{ + */ + /** + \brief append Sched + + \param p + pointer to Sched + + Appends Sched \p p at its execution time. + If there are already Sched objects scheduled at + the execution time of \p p, addSched will consider + the priorities and use the FIFO strategy. + + \sa insertSched + */ + void addSched( Sched* s ); + + /** + \brief insert Sched + + \param p + pointer to Sched + + Inserts Sched \p p at its execution time. + If there are already Sched objects scheduled at + the execution time of \p p, insertSched will consider + the priorities and use the LIFO strategy. + + \sa addSched + */ + void insertSched( Sched* s ); + + /** + \brief insert Sched \p p after \p previous + + \param p + pointer to new Sched object + + \param previous + pointer to Sched object after which the new Sched + should be inserted + + Inserts Sched \p p after the \p previous Sched object + in ExecutionList. + + \note insertSchedAfter will change the priority of + Sched \p p if necessary. + + \sa insertSchedBefore + */ + void insertSchedAfter( Sched* s, Sched* partner ); + + /** + \brief insert Sched \p p before \p next + + \param p + pointer to new Sched + + \param next + pointer to Sched before which the new Sched + should be inserted + + Inserts Sched \p p before the \p next Sched + in ExecutionList. + + \note insertSchedBefore will change the priority of + Sched \p p if necessary. + + \sa insertSchedAfter + */ + void insertSchedBefore( Sched* s, Sched* partner ); + + /** + \brief remove Sched + + Removes Sched \p p from ExecutionList. + */ + void removeSched( Sched* s ); + //@} + + /** + \brief top most Sched in ExecutionList + + \return + pointer to top most Sched in ExecutionList + */ + Sched* getNextSched() const; + + /** + * @brief Get the execution time of the first schedule entry + * @return 0 if schedule is empty + */ + SimTime getNextExecutionTime() const; + + /** + \brief check if ExecutionList is empty + */ + bool isEmpty() const; + + /** + \brief get simulation time + + \return + current simulation time + */ + SimTime getTime(); + + // Implementation +private: + /// Map type to associate simulation times with lists of scheduled objects + typedef std::map< SimTime, SchedList > Schedule; + /// Actual schedule holding pointers to Sched objects sorted by time and priority + Schedule schedule_; + + friend class Scheduler; + /** + \brief inSort Sched \p e in Sched list + + \param e + pointer to Sched + + \param fifo + use FIFO or LIFO strategy for inSort + */ + void inSort( Sched* s, bool fifo = true ); +}; + +} } // namespace odemx::base + +#endif diff --git a/odemx-lite/include/odemx/base/Process.h b/odemx-lite/include/odemx/base/Process.h new file mode 100644 index 0000000000000000000000000000000000000000..68cd6f37f757914766fd2f9692cf47f7a010f27d --- /dev/null +++ b/odemx-lite/include/odemx/base/Process.h @@ -0,0 +1,783 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Process.h + * @author Ralf Gerstenberger + * @date created at 2002/01/30 + * @brief Declaration of odemx::base::Process and observer + * @sa Process.cpp + * @since 1.0 + */ + +#ifndef ODEMX_BASE_PROCESS_INCLUDED +#define ODEMX_BASE_PROCESS_INCLUDED + +#include <odemx/base/Sched.h> +#include <odemx/base/TypeDefs.h> +#include <odemx/coroutine/Coroutine.h> +#include <odemx/data/Observable.h> +#include <odemx/synchronization/IMemory.h> +#include <odemx/util/attributes.h> +#include <odemx/synchronization/Memory.h> +#include <odemx/base/control/ControlBase.h> + +//#include <odemx/base/Control.h> + +namespace odemx { + +// forward declarations +namespace synchronization { +class ProcessQueue; +} + +namespace base { + +class ControlBase; // include follows in Process.cpp +class Simulation; +class ProcessObserver; + +/** \class Process + + \ingroup base + + \author Ralf Gerstenberger + + \brief %Process is the base class for all user processes in a model. + + \note %Process supports Observation. + \note %Process supports Trace. + + \sa Event, Condition, Selection and Simulation + + %Process is the base class for all user defined processes in a model. A user + creates a derived class for every different type of process of its model. In + its classes the user has to provide the behaviour by implementing the main() + method. The behaviour is executed according to an execution schedule + (ExecutionList) at a certain point in simulation time. If multiple processes + share the same execution time, the order of execution is defined by the way + the processes have been scheduled. A process can be scheduled with respect + to its priority FirstInFirstOut or LastInFirstOut at a point in time, or + in relation to an already scheduled partner process (immediately after or before + that process). + + \par Example: + \include basicProcess.cpp + + \since 1.0 +*/ +class Process +: public Sched // is DataProducer, etc. +, public coroutine::Coroutine +, public data::Observable< ProcessObserver > +{ +public: + /** + \brief Process states + + A process passes different process states during its life time + (between new and delete). After construction a process is CREATED. + In this state a process isn't scheduled for execution and hasn't been executed + yet. In RUNNABLE a process is scheduled for execution. If a process is executed + its state is CURRENT. In every simulation there is no more than one process + executed at a time. A process in IDLE state is not scheduled for execution. It is + inactive. If a process has finished or is terminated its state is TERMINATED. + Such a process is not scheduled for execution and cannot be scheduled + anymore. + */ + enum ProcessState + { + CREATED, ///< Initial state 0 + CURRENT, ///< Active state 1 + RUNNABLE, ///< Scheduled state 2 + IDLE, ///< Wait state 3 + TERMINATED ///< Final state 4 + }; + +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to the Simulation object + \param l + label of this object + \param o + initial observer + */ + Process( Simulation& sim, const data::Label& label, ProcessObserver* obs = 0 ); + + /// Destruction + ~Process(); + + /** + \brief Get process state + \return current process state + */ + ProcessState getProcessState() const; + + /** + \name Process Scheduling + + These functions are used to schedule a process + in simulation time. + + @{ + */ + /** + \brief Immediate activation + + This function schedules the process at the current time before + all other processes with the same priority (LIFO). If the current + process (A) does not have a higher priority than the process the + function is called for (B) the following will happen: + \li B is scheduled before A + \li the state of A changes to RUNNABLE while the state + of B changes to CURRENT + \li the main() function of A is stopped (the point is saved) + \li the main() function of B is executed from the point it + has been left last time (or from the beginning) + */ + void activate(); + + /** + \brief Activation in (relative) time \p t + \param t + delay for activation + + This function schedules the process at the simtime \c now + \p t + before all other processes with the same priority (LIFO). If + \p t is 0 this function is equal to activate(). + + \sa activate() + */ + void activateIn( SimTime t ); + + /** + \brief Activation at (absolute) time \p t + \param t + time for activation + + This function schedules the process at the simtime \p t + before all other processes with the same priority (LIFO). If + \p t is \c now this function is equal to activate(). + + \sa activate() + */ + void activateAt( SimTime t ); + + /** + \brief Activation before process \p p + \param p + pointer to partner process + + This function schedules the process just before + process \p p. If necessary the priority of the process + is changed. If \p p is this process this function + does nothing. If process \p p is not scheduled ODEMx + reports an error. + */ + void activateBefore( Sched* s ); + + /** + \brief Activation after process \p p + \param p + pointer to refrence process + + This function schedules the process just after + process \p p. If necessary the priority of this process + is changed. If \p p is this process this function + does nothing. If process \p p is not scheduled ODEMx + reports an error. + */ + void activateAfter( Sched* s ); + + /** + \brief Immediate activation (FIFO) + + This function schedules the process at the current time + after all other processes with the same priority. + */ + void hold(); + + /** + \brief Activation (FIFO) in (relative) time \p t + + This function schedules the process at the time \c now + \p t + after all other processes with the same priority. If \p t + is 0 this function is equal to hold(). + + \sa hold() + */ + void holdFor( SimTime t ); + + /** + \brief Activation (FIFO) at (absolute) time \p t + + This function schedules the process at simtime \p t + after all other processes with the same priority. If \p t + is \c now this function is equal to hold(). + + \sa hold() + */ + void holdUntil( SimTime t ); + + /** + \brief Deactivation + + This function removes the process from execution schedule + and changes its state into IDLE. The next RUNNABLE process + in the schedule is than activated. + */ + void sleep(); + + /** + \brief Interrupt + + This function interrupts the process, which results in an immediate + activation [activate()]. A Process can determine whether it was + interrupted by isInterrupted(). A Process must handle interrupts + on its own. It should do so after activate... and hold... operation. + + \sa activateAt(), activateUntil(), holdFor() and holdUntil() + */ + virtual void interrupt(); + + /** + \brief Termination + + This function terminates the process. The process is than removed from + execution schedule and its state is changed to TERMINATED. + */ + void cancel(); + //@} + + /** + \name Priority + + If the priority is changed the position of the process in the + execution schedule and in queues is updated. This can cause a + switch to another process. + + @{ + */ + /** + \brief Get priority + \return + process priority + + This function returns the current process priority. + */ + Priority getPriority() const; + + /** + \brief Set new priority + \return + previous process priority + + This function changes the process priority. The position + in the execution schedule is affected by priority changes. + */ + Priority setPriority( Priority newPriority ); + //@} + + /** + \name Execution Time + + @{ + */ + /** + \brief Get execution time + \return + execution time; 0 if not RUNNABLE or CURRENT + + This function returns the execution time of the process. + A process is scheduled for execution at its execution + time. + */ + SimTime getExecutionTime() const; + //@} + + /** + \name Current System State + + @{ + */ + /** + \brief Get currently active Sched object + \return + pointer to the current Sched object + + This function returns the currently active Sched object. + */ + Sched* getCurrentSched(); + + /** + \brief Get currently active process + \return + pointer to the current process + + This function returns the currently active process (the one + in state CURRENT). + */ + Process* getCurrentProcess(); + + /** + \brief Get current simtime + \deprecated substituted by Sched::getTime () + \return + current simulation time + + This function returns the current simulation time by simply calling + Process::getTime (). + */ + DEPRECATED(SimTime getCurrentTime() const); + + /** + \name Interrupt handling + + An Interrupt is caused by the scheduling function interrupt(). + The interrupter (Sched object) is stored. The interrupt-state is + automatically reset by the next scheduling function called. If the + Process is interrupted but the interrupter is 0, then the Process + was interrupted by the simulation (environment). + + @{ + */ + /** + \brief Get interrupt state + \return + interrupt state + + This function returns the interrupt state of the process. + */ + bool isInterrupted() const; + + /** + \brief Get process which called interrupt() + \return + pointer to process which called interrupt() + + This function returns the process which called interrupt(). + */ + Sched* getInterrupter(); + + //@} + + + /** + \name Suspend and alert + \author Ronald Kluth + + A concept of suspending a process until a resource becomes + available or a timeout occurs. + + @{ + + */ + + /** + \brief Suspend process and wait for alert + \param m0 + pointer to object of Memory-derived class, must be given + \param m1 + pointer to object of Memory-derived class, optional + \param m2 + pointer to object of Memory-derived class, optional + \param m3 + pointer to object of Memory-derived class, optional + \param m4 + pointer to object of Memory-derived class, optional + \param m5 + pointer to object of Memory-derived class, optional + + \return + pointer to alerting memo object + + This function is used to suspend a process while waiting for + one of the given Memory objects to become available. + That can either be a PortHead or PortTail, or a Timer event. + The function returns the pointer to the first available Memory object. + If the process was interrupted, this function returns 0. Hence, + a process should always check for interruption after calling \p wait(). + */ + + synchronization::IMemory* wait( synchronization::IMemory* m0, synchronization::IMemory* m1 = 0, + synchronization::IMemory* m2 = 0, synchronization::IMemory* m3 = 0, + synchronization::IMemory* m4 = 0, synchronization::IMemory* m5 = 0 ); + + /** + \brief Suspend process and wait for alert + \param memvec + vector containing pointers to objects of Memory-derived classes + \return + pointer to alerting memo object + + Overloaded version of the above function. Instead of several + pointers to Memory objects, a vector containing all the Memory + objects can be given as a parameter. + */ + + synchronization::IMemory* wait( synchronization::IMemoryVector* memvec ); + + + /** + \brief Reschedule process when a Memory object becomes available + \param theAlerter + pointer to the calling Memory object + + This function is called when Memory-derived objects call alert(). + It wakes up a suspended process and reschedules it at the + current simulation time. + */ + virtual void alertProcess( synchronization::IMemory* theAlerter ); + + /** + \brief Check alert state of the process + \return + Alert state of the process + + This function checks the alert state of the process. It returns + true if alertProcess() was called on this object. The library uses + it in Process::wait() to determine whether a process was alerted + by a Memory object. + */ + bool isAlerted() const; + + /** + \brief Determine who woke the process with an alert + \return + pointer to the available Memory object + + This function is used in Process::wait() to determine + the currently available Memory object. + */ + synchronization::IMemory* getAlerter() const; + + /** + \brief Reset the values alerted and alerter + + This function is used in Process::wait() to avoid the use + of outdated alert state or a previous alerter. It is recommended + to call this function before and after waiting and receiving + an alert. + */ + void resetInterrupt(); + +private: + void genericHoldUntil(SimTime t); + void resetAlert(); + //@} + +public: + + /** + \name Generic condition waiting + \author Jonathan Schlue + + A concept of suspending a process until an arbitrary condition turns true. + @{ + + */ + + /** + \brief This function can be used by processes to wait for arbitrary conditions. + + \param condition the condition to wait for to become true. This process will be passed as an argument to the condition. + + \param controls a list of controlled variables, which inform the Process whenever they get accessed so that the condition turned true + + \param label a label for all log entries related to this waitUntil() call + + \return + false if the process was interrupted, otherwise true + + Process execution blocks until the provided condition turns true. + All passed control variables automatically wake up this process on change to let it check its condition again. + If the condition is evaluated to true, the invoking control variable is set as this process' alerter and the process is marked as alerted. + This is mainly useful to later find the control variable, which change made the condition turn true. + However, the process can still be manually instructed to check its condition by scheduling it using methods from the activate- or hold-family. + This is mainly useful if no control variables were provided. + + + \note Once the condition turned + + \sa Control, ControlBase + + */ + bool waitUntil(const Condition& condition, const std::string label, + const std::vector<std::reference_wrapper<ControlBase>>& controls); + + //@} + +public: + /** + \brief main() function status + \return + true if the main() function has returned + + This function returns true if the main() function of + this process has returned (is finished). + */ + bool hasReturned() const; + + /** + \brief Get return value of main() function + \return + return value from main() + + This function returns the return value of the main() + function. Use the hasReturned() function to check + whether the main() function has already returned. + */ + int getReturnValue() const; + + /** + \brief Get pointer to Trace + \return + pointer to Trace object + */ + //virtual data::Trace* getTrace() const; + + /** \name Queue management + + Processes can be managed in queues during a simulation. + Typically, queues are used with FIFO-strategy. This behavior + can be influenced by setting a separate queue priority for + a process. However, this instrument should be handled with care + as a change in queue priority might lead to a Process always + being in first or last position in every queue it enters. + + Currently, each Process object can only be enqueued in one + queue at a time. + + @{ + */ + /** + \brief Get queue + \return + pointer to ProcessQueue + + If the process is in a queue this function returns + the pointer to the queue. + */ + synchronization::ProcessQueue* getQueue() const; + + /** + \brief Get enqueue-time + \return + time at which the process entered a queue + + If the process is in a queue this function returns + the time at which the process entered the queue. This + function is used by synchronisation objects. + */ + SimTime getEnqueueTime() const; + + /** + \brief Get dequeue-time + \return + time at which the process left a queue + + If the process was in a queue this function returns + the time it left the queue. This function is used by + synchronisation objects. + */ + SimTime getDequeueTime() const; + + /** + \brief Get queue priority + \return + queue priority + + This function returns the current queue priority of this process + */ + Priority getQueuePriority() const; + + /** + \brief Set new queue priority + \param newQPriority + the new priority value + \param reactivate + set to \c true to immediately activate this process + \return + previous queue priority + + This function changes the queue priority of this process. + The position in queues is affected by changes of this value. + The default is 0. If reactivate is set to true, the process + will be scheduled and activated immediately. This is useful if + a process is enqueued in a queue where it has to meet a certain + condition, or if it is moved into first position by this change. + The process will still be blocked if a required condition + could not be fulfilled. + */ + Priority setQueuePriority( Priority newQPriority, bool reactivate ); + + //@} + + +protected: + /** + \brief User defined process behaviour + + This function must be implemented by the user to define the + behaviour of a process. It is executed by ODEMx when the process + becomes the current process. If the process calls a scheduling + function (direct or indirect, at itself or another process) + the %main() function is delayed until the process is executed + again. The sequence in which different processes are executed + is determined by the execution schedule. + + \sa Process Scheduling + */ + virtual int main() = 0; + + + // Interface + + friend class ExecutionList; + /** + \brief Set execution time + \return + previous execution time + + This function is used by the library. Don't + call it directly! Use the scheduling functions + instead. + */ + SimTime setExecutionTime( SimTime time ); + + friend class Simulation; + /** + \brief Execution of this process + + This function is used by the library. Don't + call it directly! The execution is managed + by the process scheduling. + */ + void execute(); +private: + + /// Coroutine entry-point implementation + virtual void run(); + + ProcessState processState_; ///< process state + Priority priority_; ///< process priority, influences scheduling + SimTime executionTime_; ///< process execution time + ProcessList::iterator simListIter_; ///< remember position in Simulation lists + bool validReturn_; ///< return value is valid + int returnValue_; ///< return value of main() + + synchronization::ProcessQueue* queue_; ///< pointer to queue if process is waiting + SimTime enqueueTime_; ///< enqueue-time + SimTime dequeueTime_; ///< dequeue-time + Priority queuePriority_; ///< separate priority setting for queues + ProcessList::iterator queueListIter_; ///< remember position in process queues + + bool isInterrupted_; ///< Process was interrupted + Sched* interrupter_; ///< Process was interrupted by interrupter (0->by Simulation) + bool isAlerted_; ///< Process was alerted + synchronization::IMemory* alerter_; ///< Process alerter + +private: + /** + \brief set process state + \return true if successful + */ + bool setProcessState( ProcessState newState ); + + friend class synchronization::ProcessQueue; + /** + \name ProcessQueue Management + \note No more than one ProcessQueue at a time is supported. (provisional) + + @{ + */ + void enqueue( synchronization::ProcessQueue* inQueue ); ///< process enters queue \p nq + void dequeue( synchronization::ProcessQueue* outQueue ); ///< process leaves queue \p nq + //@} + + /** + \name Trace help functions + @{ + */ + /// log wait to trace with a list of memory objects + void traceWait( synchronization::IMemoryVector& memvec ); + const data::Label& getPartner(); + + static std::string stateToString( ProcessState state ); + //@} +}; + + +/** \interface ProcessObserver + + \author RalfGerstenberger + + \brief Observer for Process specific events. + + \sa Process + + \since 1.0 +*/ +class ProcessObserver: + public coroutine::CoroutineObserver +{ +public: + virtual ~ProcessObserver() {} +// virtual void onCreate( Process* sender ) {} ///< Construction +// virtual void onDestroy( Process* sender ) {} ///< Destruction + + // Activation (LIFO) + virtual void onActivate( Process* sender ) {} ///< Immediate activation + virtual void onActivateIn( Process* sender, SimTime t ) {} ///< Activation in + virtual void onActivateAt( Process* sender, SimTime t ) {} ///< Activation at + + // Activation in Releation to a Partner Process + virtual void onActivateBefore( Process* sender, Sched* p ) {} ///< Activation before + virtual void onActivateAfter( Process* sender, Sched* p ) {} ///< Activation after + + // Activation (FIFO) + virtual void onHold( Process* sender ) {} ///< hold + virtual void onHoldFor( Process* sender, SimTime t ) {} ///< Hold for + virtual void onHoldUntil( Process* sender, SimTime t ) {} ///< Hold until + + virtual void onInterrupt( Process* sender ) {} ///< Process interrupted + virtual void onSleep( Process* sender ) {} ///< Process deactivated + virtual void onCancel( Process* sender ) {} ///< Process terminated + + virtual void onExecute( Process* sender ) {} ///< Process execution was started or continued + virtual void onReturn( Process* sender ) {} ///< Process successfully returned from main() + + virtual void onWait( Process* sender, synchronization::IMemoryVector* memvec ) {} ///< Process waiting for alert + virtual void onAlert( Process* sender, synchronization::IMemory* alerter ) {} ///< Process deactivated + + /// Process state change + virtual void onChangeProcessState( Process* sender, Process::ProcessState oldState, Process::ProcessState newState ) {} + /// Process priority change + virtual void onChangePriority( Process* sender, Priority oldPriority, Priority newPriority ) {} + /// Process queue priority change + virtual void onChangeQueuePriority( Process* sender, Priority oldQPriority, Priority newQPriority ) {} + /// Process execution time change + virtual void onChangeExecutionTime( Process* sender, SimTime oldExecutionTime, SimTime newExecutionTime ) {} +}; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_PROCESS_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/Sched.h b/odemx-lite/include/odemx/base/Sched.h new file mode 100644 index 0000000000000000000000000000000000000000..ba16a4cf50d8308356af2912ff95d56779da57cf --- /dev/null +++ b/odemx-lite/include/odemx/base/Sched.h @@ -0,0 +1,226 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Sched.h + * @author Ronald Kluth + * @date created at 2007/01/24 + * @brief Declaration of odemx::base::Sched + * @sa Sched.cpp + * @since 2.0 + */ + +#ifndef ODEMX_BASE_SCHED_INCLUDED +#define ODEMX_BASE_SCHED_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/base/TypeDefs.h> +#include <odemx/data/Producer.h> + +namespace odemx { + +// forward declaration +namespace base { class Sched; } + +/** + \brief Comparison operator for Sched objects + \par first + first Process + \par second + second Process + + This operator compares two Sched objects. The + operator returns true if the execution time of + \p first is less than that of \p second. If both have the same + execution time, the priority is used. True is returned if priority + of \p first is higher than that of \p second. +*/ +extern bool operator<( const base::Sched& first, const base::Sched& second ); + +namespace base { + +// forward declaration +class ExecutionList; + +/** \class Sched + + \ingroup base + + \author Ronald Kluth + + \brief %Sched is the interface for all schedulable objects in a model. + + \sa Simulation, ExecutionList, Event, Process + + %Sched is the abstract base class for all schedulable bjects. + It declares all functions needed for the scheduling + mechanism of ODEMx. This layer of abstraction was inserted to allow + scheduling of different kinds of objects. The schedule works on + polymorphic pointers of type Sched. The library supports event-based + as well as process-based simulation models. Event and Process are + Sched-derived classes that implement the interface. + + \since 2.0 +*/ +class Sched +: public data::Producer +{ +public: + /** + \brief Sched types + + Sched types are a means to handle the execution of different + types of simulation objects, in this case Events and Processes. + When different kinds of objects can be scheduled, the Simulation + has to decide how to proceed when the simulation time reaches the + execution time of an object. + */ + enum SchedType + { + PROCESS, ///< Simulation must start this process's coroutine + EVENT ///< Simulation only needs to execute an event action + }; + +public: + + /** + \brief Construction + \param st + type of the schedulable object, from enum Sched::SchedType + */ + Sched( Simulation& sim, const data::Label& label, SchedType st ); + + /// Destruction + virtual ~Sched(); + + /** + \name Scheduling interface + + These functions are used by the ExecutionList to schedule objects + according to their execution time and their priority. Every + class of schedulable objects must implement these pure virtual + functions. + + @{ + */ + /** + \brief Get execution time + \return + execution time of the object + + This function returns the execution time of the Sched object. + Processes and Events are scheduled for execution at their execution + time. + */ + virtual SimTime getExecutionTime() const = 0; + + /** + \brief Set execution time + \return + previous execution time + + This internal function is used by the library. It should + never be called directly! Use scheduling functions instead. + */ + virtual SimTime setExecutionTime( SimTime time ) = 0; + + /** + \brief Get priority + \return + scheduling priority + + This function returns the current Sched priority. + If the priority is changed, the position of the object in the + execution schedule and in queues is updated. This can cause a + switch to another Sched object. + */ + virtual Priority getPriority() const = 0; + + /** + \brief Set new priority + \return + previous Sched priority + + This function changes the scheduling priority. The position + in the execution schedule and in queues is affected by + priority changes. + */ + virtual Priority setPriority( Priority newPriority ) = 0; + + /** + \brief Check if Sched object is in schedule + + This function checks a boolean member which is set to true + when a scheduling function was called on this event. + */ + bool isScheduled() const; + //@} + + /** + \name Sched execution + + These functions are used to schedule a process + in simulation time. + + @{ + */ + /** + \brief Determine the Sched object's type + \returns + SchedType of this schedulable Object + + The type of Sched objects cannot change, it is set in + the constructors of Event and Process. This internal + function is used during simulation computation to + determine the the correct path of execution for this object. + */ + + SchedType getSchedType() const; + + /** + \brief Execution of Sched object + + This virtual function is used polymorphically by Simulation + to execute the current Sched object. + + \sa getSchedType(), Simulation::exec() + */ + virtual void execute() = 0; + //@} + + /** + \brief Get current simtime + \return + current simulation time + + This function returns the current simulation time. + */ + SimTime getTime() const; +private: + SchedType schedType_; ///< Event or Process + bool scheduled_; ///< determine whether the object is scheduled + std::pair< SimTime, SchedList* > scheduleLoc_; + SchedList::iterator execListIter_; ///< remember position in ExecutionList + + friend class ExecutionList; + friend bool odemx::operator<( const base::Sched& first, const base::Sched& second ); +}; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_SCHED_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/Scheduler.h b/odemx-lite/include/odemx/base/Scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..1bd757cfa1132ee5bfa6ca44c35a5bfdcf752b51 --- /dev/null +++ b/odemx-lite/include/odemx/base/Scheduler.h @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Scheduler.h + * @author Ronald Kluth + * @date created at 2009/03/12 + * @brief Declaration of odemx::base::Scheduler + * @sa Scheduler.cpp + * @since 3.0 + */ + +#include <odemx/base/ExecutionList.h> +#include <odemx/base/SimTime.h> +#include <odemx/data/Producer.h> + +#ifndef ODEMX_BASE_SCHEDULER_INCLUDED +#define ODEMX_BASE_SCHEDULER_INCLUDED + +namespace odemx { +namespace base { + +class Simulation; + +/** + * @brief Internal class used by the simulation context to manage scheduling and execution + */ +class Scheduler +: public data::Producer +{ +public: + Scheduler( Simulation& sim, const data::Label& label ); + ~Scheduler(); + + void run(); + void runUntil( SimTime stopTime ); + void step(); + + void addSched( Sched* s ); + void insertSched( Sched* s ); + void insertSchedBefore( Sched* s, Sched* partner ); + void insertSchedAfter( Sched* s, Sched* partner ); + void removeSched( Sched* s ); + + const ExecutionList& getExecutionList() const; + +private: + Simulation& sim_; + ExecutionList executionList_; + +protected: + // allow Sched-derived classes access to private members + friend class Process; + friend class Event; + + void inSort( Sched* s ); + void executeNextSched(); +}; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_SCHEDULER_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/SimTime.h b/odemx-lite/include/odemx/base/SimTime.h new file mode 100644 index 0000000000000000000000000000000000000000..c269283b310eae0add066a784c539409eebcb05b --- /dev/null +++ b/odemx-lite/include/odemx/base/SimTime.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimTime.h + * @author Ralf Gerstenberger + * @date created at 2002/01/24 + * @brief TypeDef of odemx::base::SimTime + * + * The simulation time is an abstraction from real time. It is also referred to + * as model time. + * + * @since 1.0 + */ + +#ifndef ODEMX_BASE_SIMTIME_INCLUDED +#define ODEMX_BASE_SIMTIME_INCLUDED + +#include <odemx/setup.h> + +namespace odemx { +namespace base { + +#ifdef ODEMX_USE_CONTINUOUS + typedef double SimTime; ///< Simulation time type +#else + // changed in odemx-lite, was Poco::UInt64 (this is a platform dependend type.) + typedef long long SimTime; ///< Simulation time type +#endif + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_SIMTIME_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/Simulation.h b/odemx-lite/include/odemx/base/Simulation.h new file mode 100644 index 0000000000000000000000000000000000000000..887814ae22178ad026ffd96a875943fedacdbec4 --- /dev/null +++ b/odemx-lite/include/odemx/base/Simulation.h @@ -0,0 +1,436 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Simulation.h + * @author Ralf Gerstenberger + * @date created at 2002/02/22 + * @brief Declaration of odemx::base::Simulation and observer + * @sa Simulation.cpp + * @since 1.0 + */ + +#ifndef ODEMX_BASE_SIMULATION_INCLUDED +#define ODEMX_BASE_SIMULATION_INCLUDED + +#include <odemx/base/Scheduler.h> +#include <odemx/base/SimTime.h> +#include <odemx/coroutine/CoroutineContext.h> +#include <odemx/data/Label.h> +#include <odemx/data/Producer.h> +#include <odemx/data/LoggingManager.h> +#include <odemx/random/DistContext.h> +#include <odemx/data/Observable.h> +#include <odemx/util/attributes.h> + +#include <list> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + + +// forward declaration, this class is used in unit tests +class TestSimulation; + +namespace odemx { +namespace base { + +// forward declarations +class Event; +class Process; +class DefaultLogConfig; +class SimulationObserver; + +/** \class Simulation + + \ingroup base + + \author Ralf Gerstenberger + + \brief %Simulation is the base class for all user simulations. + + \note %Simulation supports Observation. + \note %Simulation supports Trace. + + In a user simulation + the method initSimulation() must be implemented to set-up the + simulation. run(), step() or runUntil() can be used to compute the + simulation. run() returns after the simulation has finished. step() + returns after each execution of a scheduled object in the simulation. + runUntil() returns + after simulation time exceeds the given time or the simulation is finished. + %Simulation also manages lists of all Process objects in the states + CREATED, RUNNABLE, IDLE and TERMINATED. + + \par Example: + \include matryoshka.cpp + + \since 1.0 +*/ +class Simulation +: public data::LoggingManager // must be initialized first, because +, public data::Producer // Producer needs Context for initialization +, public coroutine::CoroutineContext +, public random::DistContext +, public data::Observable< SimulationObserver > +{ +public: + /// Process list identifiers + enum List + { + CREATED, ///< Created processes + RUNNABLE, ///< Runnable processes + IDLE, ///< Idle processes + TERMINATED ///< Terminated processes + }; + +public: + /** + \brief Construction + \param l + label of this object + \param o + initial observer + */ + Simulation( const data::Label& label = "Simulation", SimulationObserver* obs = 0 ); + + /** + \brief Construction + \param l + label of this object + \param o + initial observer + */ + Simulation( const data::Label& label, SimTime startTime, SimulationObserver* obs = 0 ); + + /// Destruction + virtual ~Simulation(); + + /// Describe the purpose of the simulation + void setDescription( const std::string& description ); + + /// Get the simulation description + const std::string& getDescription() const; + + /** + \name Simulation computing + + The computation of a simulation is started with one of + the following functions. A simulation is finished when there is + no Sched object left to be executed or the function exitSimulation() + was called. + + @{ + */ + /// Run simulation until it is finished + void run(); + /// Execute one scheduled object and return + void step(); + /// Run until the current time reaches the \c stopTime + void runUntil( SimTime stopTime ); + + /** + \brief Simulation status + \return + true if simulation is finished + + This function returns true if the simulation is finished. + */ + bool isFinished() const; + + /** + \brief Stop simulation + + This function stops the simulation. + */ + virtual void exitSimulation(); + + //@} + + /** + \name Process management + + Simulation remembers all process objects. The following + functions can be used to get the objects in different + process states. + + \sa Process::ProcessState + + @{ + */ + /** + \brief Get currently executed process + \return + pointer to executed process object + + This function returns a pointer to the momentarily + executed process (the process in state CURRENT). + */ + Process* getCurrentProcess(); + + /** + \brief Get currently executed Sched object + \return + pointer to executed Sched object + + This function returns a pointer to the momentarily + executed object. That can either be the process in + state CURRENT, or the currently running event. + */ + Sched* getCurrentSched(); + + void resetCurrentSched(); + void resetCurrentProcess(); + + /** + \brief Get list of processes in state CREATED + \return + list of processes in state CREATED + + This function returns a list of all processes + in state CREATED. + */ + DEPRECATED(ProcessList& getCreatedProcesses()); + /** + \brief Get list of processes in state CREATED + \return + list of processes in state CREATED + + This function returns a list of all processes + in state CREATED. + */ + const ProcessList& getCreatedProcesses() const; + /** + \brief Get list of processes in state RUNNABLE + \return + list of processes in state RUNNABLE + + This function returns a list of all processes + in state RUNNABLE. + */ + DEPRECATED(ProcessList& getRunnableProcesses()); + /** + \brief Get list of processes in state RUNNABLE + \return + list of processes in state RUNNABLE + + This function returns a list of all processes + in state RUNNABLE. + */ + const ProcessList& getRunnableProcesses() const; + + /** + \brief Get list of processes in state IDLE + \deprecated Please use the overloads instead. + \return + list of processes in state IDLE + + This function returns a list of all processes + in state IDLE. + */ + DEPRECATED(ProcessList& getIdleProcesses()); + /** + \brief Get list of processes in state IDLE + \return + list of processes in state IDLE + + This function returns a list of all processes + in state IDLE. + */ + const ProcessList& getIdleProcesses() const; + + /** + \brief Get list of processes in state TERMINATED + \return + list of processes in state TERMINATED + + This function returns a list of all processes + in state TERMINATED. + */ + DEPRECATED(ProcessList& getTerminatedProcesses()); + /** + \brief Get list of processes in state TERMINATED + \return + list of processes in state TERMINATED + + This function returns a list of all processes + in state TERMINATED. + */ + const ProcessList& getTerminatedProcesses() const; + + /** + * @brief Controls whether all terminated processes are delete automatically + * + * After each object execution, the scheduler tests if this property is + * activated. In that case, it proceeds by deleting all processes stored + * in the list @c terminatedProcesses_ and clears the list. + * + * @warning This feature MUST NOT be used if you allocate processes objects + * on the runtime stack because @c delete calls are not allowed. + * @warning This feature is unsafe! It should only be used if the memory + * taken up by finished processes is really needed. You will not be able + * to access pointers or references to processes in your simulation program + * after process termination. + */ + void autoDeleteProcesses( bool value = true ); + //@} + + /** + \brief Get current simulation time + \return + time now + + This function returns the current simulation time. + The current time is determined by the current or + last executed process. If a process is executed its + execution time becomes the new simulation time. + */ + SimTime getTime() const; + + /// Used by the Scheduler to adjust the simulation time + void setCurrentTime( SimTime newTime ); + + /** + \brief Get initial simulation time + \return + time start + + This function returns the initial simulation time, which + can only be set in the constructor. + */ + SimTime getStartTime() const; + + /** + \brief Get a reference to the scheduler + \return + reference to the scheduler + */ + Scheduler& getScheduler(); + + /// Get the unique identifier of a simulation object + SimulationId getId() const; + +protected: + /** + \brief Initialization of a simulation + + Implement this method to initialize a simulation. + One can create and activate the first processes of + a simulation in this function. Inside this + function the scheduling operations does not cause + an immediate execution of a process. The first process + is executed after this function is finished. + */ + virtual void initSimulation() = 0; + +private: + // needed for unit testing + friend class TestSimulation; + + std::string description_; ///< simulation description + bool isInitialized_; ///< simulation is initialized + bool isStopped_; ///< simulation is stopped + SimTime startTime_; ///< start time offset for simulation, default is 0 + SimTime currentTime_; ///< current time + + Scheduler scheduler_; ///< manages execution of events and processes + Process* currentProcess_; ///< current process on stack + Sched* currentSched_; ///< current scheduled object: event or process + ProcessList createdProcesses_; ///< CREATED processes + ProcessList runnableProcesses_; ///< RUNNABLE processes + ProcessList idleProcesses_; ///< IDLE processes + ProcessList terminatedProcesses_; ///< TERMINATED processes + bool autoDelete_; ///< determines whether finished process objects are deleted + SimulationId uniqueId_; ///< stores a unique identifier for each simulation + +private: + + friend class Process; + friend class Event; + friend class Scheduler; + + /** + \name Process/Event Management + @{ + */ + void setCurrentSched( Sched* s ); + void setCurrentProcess( Process* p ); + void setProcessAsCreated( Process* p ); + void setProcessAsRunnable( Process* p ); + void setProcessAsIdle( Process* p ); + void setProcessAsTerminated( Process* p ); + //@} + + /** + \name Help procedures + @{ + */ + void init(); + void removeProcessFromList( Process* p ); + void checkAutoDelete(); + //@} +}; + +/** \interface SimulationObserver + + \author Ralf Gerstenberger + + \brief Observer for Simulation events + + \since 1.0 +*/ +class SimulationObserver +: public coroutine::CoroutineContextObserver +{ +public: + /// Construction +// virtual void onCreate( Simulation* sender ) {} + + /// Initialisation + virtual void onInitialization( Simulation* sender ) {} + /// Termination + virtual void onExitSimulation( Simulation* sender ) {} + /// Run simulation + virtual void onRun( Simulation* sender ) {} + /// Step through simulation + virtual void onStep( Simulation* sender ) {} + /// Run simulation until time t + virtual void onRunUntil( Simulation* sender, SimTime t ) {} + + /** + \brief Change of current sched + \warning + \p oldCurrent or \p newCurrent may be 0 + */ + virtual void onChangeCurrentSched( Simulation* sender, + Sched* oldCurrent, Sched* newCurrent ) {} + + /// Process changed list + virtual void onChangeProcessList( Simulation* sender, + Process* p, Simulation::List l ) {} + + /// Time change + virtual void onChangeTime( Simulation* sender, + SimTime oldTime, SimTime newTime ) {} +}; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_SIMULATION_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/TypeDefs.h b/odemx-lite/include/odemx/base/TypeDefs.h new file mode 100644 index 0000000000000000000000000000000000000000..0c966ef71a28f30e77b24660c7fc6b720fe14f41 --- /dev/null +++ b/odemx-lite/include/odemx/base/TypeDefs.h @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TypeDefs.h + * @author Ronald Kluth + * @date created at 2009/02/13 + * @brief Declaration of types SchedList, ProcessList, Priority, SimulationId + * @since 3.0 + */ + +#ifndef ODEMX_BASE_TYPEDEFS_INCLUDED +#define ODEMX_BASE_TYPEDEFS_INCLUDED + +#include <list> +#include <functional> + +#include <odemx/base/SimTime.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace base { + +class Process; +class Sched; + +//-----------------------------------------------------------header declarations + +/// List type to hold scheduled objects in order +typedef std::list< Sched* > SchedList; + +/// List type to store process objects +typedef std::list< Process* > ProcessList; + +/// ID type to provide simulation objects with unique IDs +typedef int SimulationId; // changed in odemx-lite from Poco::UUID + +/** + * @brief Numeric type to express scheduling and queueing priority + * + * The type Priority is used to set a priority for processes and events, which + * allows users to influence scheduling or queueing order. + */ +typedef double Priority; + + +/** + \brief Generic function type for coding conditions + \param subject + pointer to process upon which the condition is applied. + + This generic function type is used for coding + conditions. The condition-function should return true + if the condition is fulfilled. + + Usally use the this pointer when a Process itself passes some condition in form of lambda expression. +*/ +typedef std::function<bool(Process* subject)> Condition; + +/** + \brief Generic function type for coding selections + \param master + pointer to master to select + \param slave + pointer to slave to select + + This Generic function type is used for coding + selections. The condition-function should return true + if the \p partner process fits the selection concerning \p master. +*/ +typedef std::function<bool(Process* master, Process* slave)> Selection; + +/** + \brief Generic function type for coding Process weight functions + \param master + pointer to master to weight + \param slave + pointer to slave to weight + + This generic function type is used for coding + a weight function to determine the importance of the partner process. + The weight function should return a higher number for a higher degree + of importance. This type of function is used in the implementation of + WaitQ to synchronize processes according to their highest weight in + relation to each other. +*/ +typedef std::function<double(Process* master, Process* slave)> Weight; + +/** + \brief Generic function type for coding Process weight functions + \param master + pointer to master to weight + \param slave + pointer to slave to weight + + This generic function type is used for coding + a weight function to determine the importance of the partner process. + The weight function should return a higher number for a higher degree + of importance. This type of function is used in the implementation of + WaitQ to synchronize processes according to their highest weight in + relation to each other. +*/ +typedef std::function<void(odemx::base::SimTime t)> Derivative; + +} } // namespace odemx::base + +#endif /* ODEMX_BASE_TYPEDEFS_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/cellular_automaton/Cell.h b/odemx-lite/include/odemx/base/cellular_automaton/Cell.h new file mode 100644 index 0000000000000000000000000000000000000000..620d23420acd75d66286f4fdae2030a19a43cd48 --- /dev/null +++ b/odemx-lite/include/odemx/base/cellular_automaton/Cell.h @@ -0,0 +1,555 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Cell.h + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Declaration of Cell + \sa CellContainer, CellMonitor, Transition + \since 3.0 + */ + +#ifndef ODEMX_CELL_INCLUDED +#define ODEMX_CELL_INCLUDED + +#include <vector> +#include <list> +#include <map> +#include <string> + +namespace odemx { + namespace base { + namespace cellular { + + class Cell; + + class ComparePositions; + + /** \class CellPosition + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling the position of one cell in the cellular automaton. + + \sa Cell + */ + class CellPosition { + public: + /** \brief Construction + \param row + row-position of the cell + \param column + column-position of the cell + \param level + level-position of the cell + \param cellRows + number of rows that belong to the grid of the cellular automaton + \param cellColumns + number of columns that belong to the grid of the cellular automaton + \param cellLevel + number of levels that belong to the grid of the cellular automaton + */ + CellPosition(unsigned row, unsigned column, unsigned level, unsigned cellRows, unsigned cellColumns, unsigned cellLevel) + : row(row) + , column(column) + , level(level) + , cellRows(cellRows) + , cellColumns(cellColumns) + , cellLevel(cellLevel) + {} + + /** \brief Construction + */ + CellPosition() + : row(0) + , column(0) + , level(0) + , cellRows(0) + , cellColumns(0) + , cellLevel(0) + {} + + /** \brief Sets the position of the cell. + \param row + row that belongs to the cell + \param column + column that belongs to the cell + \param level + level that belongs to the cell + */ + void setPosition(unsigned row, unsigned column = 0, unsigned level = 0) { + this->row = row; + this->column = column; + this->level = level; + } + + /** \brief Sets the grid size of the cellular automaton. + \param cellRows + number of rows that belong to the grid of the cellular automaton + \param cellColumns + number of columns that belong to the grid of the cellular automaton + \param cellLevel + number of levels that belong to the grid of the cellular automaton + */ + void setGridSize(unsigned cellRows, unsigned cellColumns, unsigned cellLevel) { + this->cellRows = cellRows; + this->cellColumns = cellColumns; + this->cellLevel = cellLevel; + } + + /** \brief Returns the row number that belongs to the cell. + */ + unsigned getRowNumber() { + return this->row; + } + /** \brief Returns the column number that belongs to the cell. + */ + unsigned getColumnNumber() { + return this->column; + } + /** \brief Returns the level number that belongs to the cell. + */ + unsigned getLevelNumber() { + return this->level; + } + /** \brief Returns the number of rows that belong to the grid of the cellular automaton. + */ + unsigned getNumberOfCellRows() { + return cellRows; + } + /** \brief Returns number of columns that belong to the grid of the cellular automaton. + */ + unsigned getNumberOfCellColumns() { + return cellColumns; + } + /** \brief Returns number of levels that belong to the grid of the cellular automaton. + */ + unsigned getNumberOfCellLevels() { + return cellLevel; + } + private: + /* row of the cell + */ + unsigned row; + + /* column of the cell + */ + unsigned column; + + /* level of the cell + */ + unsigned level; + + /* number of rows of the grid + */ + unsigned cellRows; + + /* number of columns of the grid + */ + unsigned cellColumns; + + /* number of levels of the grid + */ + unsigned cellLevel; + + friend class Cell; + friend class ComparePositions; + }; + + /** \class ComparePositions + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling comparisons between to CellPosition-objects. + + \sa Cell + */ + class ComparePositions { + public: + /** \brief Overrides the ()-operator to compare two CellPosition-objects. + \param cellPosition1 + first object to compare + \param cellPosition2 + second object to compare + */ + bool operator()(const CellPosition& cellPosition1, const CellPosition& cellPosition2) { + return (cellPosition1.cellRows*(cellPosition1.level*cellPosition1.cellColumns + cellPosition1.column) + cellPosition1.row) < + (cellPosition2.cellRows*(cellPosition2.level*cellPosition2.cellColumns + cellPosition2.column) + cellPosition2.row); + } + }; + + //forward declaration + class CellVariablesContainer; + class CellMonitor; + class Transition; + + struct typeOfNeighborhood; + + /** \class Cell + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling one cell in the grid of the cellular automaton. + + \sa CellMonitor, CellVariablesContainer, Transition + */ + class Cell { + public: + /** \brief Construction + \param row + row-position of the cell + \param column + column-position of the cell + \param level + level-position of the cell + \param dimension + number of the state variables of this cell + \param inputDimension + number of the input variables of this cell + \param outputDimension + number of the output variables of this cell + \param monitor + the monitor which manages this cell + */ + Cell(unsigned row, unsigned column, unsigned level, unsigned dimension, unsigned inputDimension, unsigned outputDimension, CellMonitor* monitor); + + /// destruction + virtual ~Cell(); + + /** \brief Calculates the cells in the neighborhood of one cell. Different neighborhood types can be used. + \note See CellMonitor.h for possible neighborhood types. + */ + void calculateNeighborhood(); + + /** \brief Pushes the values for neighbor cells. + */ + void pushValue(); + + /** \brief Returns the output values from neighbor cells. + \param variableIndex + index of the variables (range 0...(outputDimension-1)) + */ + std::vector<double> pullValue(unsigned variableIndex); + + /** \brief Sets the value of one state variable. + \param variableIndex + index of the variable to be set to the \p value (range 0...(stateDimension-1)) + \param value + the value to be set + */ + void setValue(unsigned variableIndex, double value); + + /** \brief Returns the value of one state variable. + \param variableIndex + index of the returned variable (range 0...(stateDimension-1)) + */ + double getValue(unsigned variableIndex); + + /** \brief Sets the value of one output variable. + \param variableIndex + index of the variable to be set to the \p value (range 0...(outputDimension-1)) + \param value + the value to be set + */ + void setOutputValue(unsigned variableIndex, double value); + + /** \brief Returns the value of one output variable. + \param variableIndex + index of the returned variable (range 0...(outputDimension-1)) + */ + double getOutputValue(unsigned variableIndex); + + /** \brief Sets the value of one input variable. + \param variableIndex + index of the variable to be set to the \p value (range 0...(inputDimension-1)) + \param value + the value to be set + */ + void setInputValue(unsigned variableIndex, double value); + + /** \brief Returns the value of one input variable. + \param variableIndex + index of the returned variable (range 0...(inputDimension-1)) + */ + double getInputValue(unsigned variableIndex); + + /** \brief Sets the transition object which contains the transition and output function of the cell. + \param transition + transition and output function of the cell + */ + void setTransition(Transition* transition); + + /** \brief Deletes transition object which contains the transition and output function of the cell. + \param transition + transition and output function of the cell + */ + void deleteTransition(Transition* transition); + + /** \brief Returns the dimension of the state variables. + */ + unsigned getDimension(); + + /** \brief Returns the dimension of the input variables. + */ + unsigned getInputDimension(); + + /** \brief Returns the dimension of the output variables. + */ + unsigned getOutputDimension(); + + /** \brief Makes the cell part of the boundary. + */ + void setIsBoundary(); + + /** \brief Is showing if the cell is part of the boundary or not (true means is part of the boundary and false means regular cell). + */ + bool isPartOfBoundary(); + + /** \brief Sets the position of the cell. + \param row + row that belongs to the cell + \param column + column that belongs to the cell + \param level + level that belongs to the cell + */ + void setPosition(unsigned row, unsigned column = 0, unsigned level = 0); + + /** \brief Returns a CellPosition-object-pointer with the position of the cell. + */ + CellPosition* getPosition(); + + /** \brief Sets the settings for the neighborhood. + \param neighborhoodType + type of the neighborhood + \param radius + radius of the neighborhood (1,....) + \param calcNeighborhood + if true the neighborhood must be calculated again after setting + + \note For possible values of neighborhoodType take a look in CellMonitor.h + The default values are neighborhoodType = MOORE and radius = 1. + */ + void setNeighborhoodSettings(unsigned neighborhoodType, unsigned radius, bool calcNeighborhood = true); + + /** \brief Returns a map with pointers to the cells in the neighborhood of one cell characterized by the position (saved in the key of the map). + */ + std::map<CellPosition, Cell*, ComparePositions> getNeighbors(); + + /** \brief It returns a cell-object-pointer if the cell with given position is in the neighborhood. Otherwise it returns 0. + \param row + row-position of the cell + \param column + column-position of the cell + \param level + level-position of the cell + */ + Cell* searchNeighbor(unsigned row, unsigned column = 0, unsigned level = 0); + + private: + /** + \brief Calculates the Moore neighborhood of the cell. + N_(i,j)={(k,l) \in L | |k-i| <= r and |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateMooreNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Von-Neumann-neighborhood of the cell. + N_(i,j)={(k,l) \in L | |k-i| + |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateVonNeumannNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Moore neighborhood of the cell. The grid of the cellular automaton is a 2-d-grid which forms a torus. + That means along the x-axis and the y-axis the grid has periodic boundaries. + N_(i,j)={(k,l) \in L | |k-i| <= r and |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateMoore2DTorusNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Moore neighborhood of the cell. The grid of the cellular automaton is a 2-d-grid which forms a tube. + That means along the x-axis the grid has periodic boundaries. + N_(i,j)={(k,l) \in L | |k-i| <= r and |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateMoore2DXAxisTubeNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Moore neighborhood of the cell. The grid of the cellular automaton is a 2-d-grid which forms a tube. + That means along the y-axis the grid has periodic boundaries. + N_(i,j)={(k,l) \in L | |k-i| <= r and |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateMoore2DYAxisTubeNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Von-Neumann-neighborhood of the cell. The grid of the cellular automaton is a 2-d-grid which forms a torus. + That means along the x-axis and the y-axis the grid has periodic boundaries. + N_(i,j)={(k,l) \in L | |k-i| + |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateNeumann2DTorusNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Von-Neumann-neighborhood of the cell. The grid of the cellular automaton is a 2-d-grid which forms a tube. + That means along the x-axis the grid has periodic boundaries. + N_(i,j)={(k,l) \in L | |k-i| + |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateNeumann2DXAxisTubeNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the Von-Neumann-neighborhood of the cell. The grid of the cellular automaton is a 2-d-grid which forms a tube. + That means along the y-axis the grid has periodic boundaries. + N_(i,j)={(k,l) \in L | |k-i| + |l-j| <= r } + \param radius + radius of the neighborhood + */ + void calculateNeumann2DYAxisTubeNeighborhood(unsigned radius = 1); + + /** + \brief Calculates the user-defined-neighborhood of the cell. The user has to define this neighborhood in a class, which is derived from the class Transition. + \param radius + radius of the neighborhood + */ + void calculateAlternativeNeighborhood(unsigned radius = 1); + + /** \brief Checks if an index exceeds the corresponding index boundary and throws an index out of bounds exception. + \param index + the index will be checked using the variable indexBoundary + \param indexBoundary + the value of the index boundary + \param std::string what + which index is out of boundary + */ + void checkIndexBoundary(unsigned index, unsigned indexBoundary, std::string what); + + /** \brief Sets the base index of the state variables of the cell + \param baseIndex + state base index of the cell + */ + void setBaseIndex(unsigned baseIndex); + + /** \brief Sets the input base index of the input variables of the cell. + \param baseIndex + input base index of the cell + */ + void setInputBaseIndex(unsigned baseIndex); + + /** \brief Sets the output base index of the output variables of the cell. + \param baseIndex + output base index of the cell + */ + void setOutputBaseIndex(unsigned baseIndex); + + /** \brief Returns the base index of the state variables of the cell. + */ + unsigned getBaseIndex(); + + /** \brief Returns the base index of the input variables of the cell. + */ + unsigned getInputBaseIndex(); + + /** \brief Returns the base index of the output variables of the cell. + */ + unsigned getOutputBaseIndex(); + + /** \brief Sets the monitor to whom the Cell-object belongs. + \param monitor + monitor of the cellular automaton + */ + void setMonitor(CellMonitor* monitor); + + /** \brief Returns the monitor to whom the Cell-object belongs. + */ + CellMonitor* getMonitor(); + + private: + + // Monitor to whom the cell belongs. + CellMonitor* monitor; + + // This object saves the indexes of the cell and the grid size of the cellular automaton. + CellPosition* cellPosition; + + /** \brief This structure saves the settings for the neighborhood of the cell. + \param + radius of the neighborhood (1,....) + \param neighborhoodType + type of the neighborhood + + \note For possible values of neighborhoodType take a look in CellMonitor.h + The default values are neighborhoodType = MOORE and radius = 1. + */ + struct neighborhoodSettings + { + unsigned neighborhoodType; + unsigned radius; + } typeOfNeighborhood; + + // Base indexes of the input, output and state variables of the cell. + unsigned int stateBaseIndex; + unsigned int inputBaseIndex; + unsigned int outputBaseIndex; + + // Dimensions of the input, output and state variables of the cell. + unsigned int stateDimension; + unsigned int inputDimension; + unsigned int outputDimension; + + // Map of the Cell-object-pointers in the neighborhood. + std::map<CellPosition, Cell*, ComparePositions> neighborhoodCellsMap; + + // List of all transition functions which belong to this instance. + std::list<Transition*> transitions; + + /** \brief Transition object to compute state changes and handle alternative neighborhoods. + */ + //Transition* transition;TODO!! + + // Is showing if the cell is part of the boundary or not. + bool isBoundary; + + // Is showing if the cell received values from neighborhood cells. + bool pushed; + + friend class CellMonitor; + }; + } +} +} +#endif diff --git a/odemx-lite/include/odemx/base/cellular_automaton/CellMonitor.h b/odemx-lite/include/odemx/base/cellular_automaton/CellMonitor.h new file mode 100644 index 0000000000000000000000000000000000000000..3d1423a95815c2bae604d6b9d9ed80bcc4091d14 --- /dev/null +++ b/odemx-lite/include/odemx/base/cellular_automaton/CellMonitor.h @@ -0,0 +1,473 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file CellMonitor.h + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Declaration of CellMonitor + + \since 3.0 + */ + +#ifndef ODEMX_CELLMONITOR_INCLUDED +#define ODEMX_CELLMONITOR_INCLUDED + +#include <list> +#include <odemx/base/Process.h> +#include <odemx/base/cellular_automaton/Transition.h> + +// Use these macros to define a neighborhood type. +#define MOORE 0 +#define NEUMANN 1 +#define MOORETORUS 2 +#define NEUMANNTORUS 3 +#define MOOREXTUBE 4 +#define NEUMANNXTUBE 5 +#define MOOREYTUBE 6 +#define NEUMANNYTUBE 7 +#define ALTERNATIVENEIGHBORHOOD 8 + +#define ROWSPAN(FROM, TO) CellIndexSpan(FROM, TO) +#define COLUMNSPAN(FROM, TO) CellIndexSpan(FROM, TO) +#define LEVELSPAN(FROM, TO) CellIndexSpan(FROM, TO) + +// Use this macro to set one transition object to the cells given by the from and to parameters of the macro. +#define _setTransitionToCells(rowIndexSpan, columnIndexSpan, levelIndexSpan, monitorName, transitionType) { \ + if(rowIndexSpan.getIndexTo() > monitorName->getRowCount()-1) {\ + throw std::out_of_range("The right side of the row index span is greater than the number of rows");\ + }\ + if(rowIndexSpan.getIndexFrom() < 0) {\ + throw std::out_of_range("The left side of the row index span is less than 0");\ + }\ + if(columnIndexSpan.getIndexTo() > monitorName->getColumnCount()-1) {\ + throw std::out_of_range("The right side the column index span is greater than the number of columns");\ + }\ + if(columnIndexSpan.getIndexFrom() < 0) {\ + throw std::out_of_range("The left side the column index span is less than 0");\ + }\ + if(levelIndexSpan.getIndexTo() > monitorName->getLevelCount()-1) {\ + throw std::out_of_range("The right side the level index span is greater than the number of levels");\ + }\ + if(levelIndexSpan.getIndexFrom() < 0) {\ + throw std::out_of_range("The left side the level index span is less than 0");\ + }\ + for (int i = rowIndexSpan.getIndexFrom(); i <= rowIndexSpan.getIndexTo(); i++) { \ + for (int j = columnIndexSpan.getIndexFrom(); j <= columnIndexSpan.getIndexTo(); j++) { \ + for (int k = levelIndexSpan.getIndexFrom(); k <= levelIndexSpan.getIndexTo(); k++) { \ + monitorName->getCell(monitorName->getLevelCount() * (monitorName->getColumnCount() * i + j) + k)->setTransition(new transitionType());\ + } \ + } \ + } \ +} + +namespace odemx { + namespace base { + namespace cellular { + /** \class CellPosition + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling the index span of row, column and level span in the cellular automaton. + + \sa CellMonitor + */ + class CellIndexSpan { + public: + /** \brief Construction + \param indexFrom + start-index of the span + \param indexTo + end-index of the span + */ + CellIndexSpan(unsigned indexFrom, unsigned indexTo) + : indexFrom(indexFrom) + , indexTo(indexTo) + {} + + /** \brief Returns the first value of the index span. + */ + unsigned getIndexFrom() { + return this->indexFrom; + } + /** \brief Returns the second value of the index span. + */ + unsigned getIndexTo() { + return this->indexTo; + } + + private: + /* row of the cell + */ + unsigned indexFrom; + + /* column of the cell + */ + unsigned indexTo; + }; + + //forward declaration + class CellVariablesContainer; + + class Cell; + + class Transition; + + class CellMonitorObserver; + + /** \class CellMonitor + + \ingroup base + + \author Sascha Qualitz + + \note %CellMonitor supports Observation. + \note %CellMonitor supports Trace. + \note %CellMonitor supports Logging. + + \brief A CellMonitor is used to generate a cellular automaton and manage it during a simulation. + + %One have to use the getter-methods to get one cell object to make changes on it. + + \sa CellularAutomaton, CellVariablesContainer, Cell, Transition, Process + + \since 3.0 + */ + class CellMonitor : public Process, public data::Observable<CellMonitorObserver> { + public: + /** \brief Construction + \param sim + reference to one simulation-object + \param l + label of this object + \param variablesInCount + number of the input variables of the cells + \param variablesOutCount + number of the output variables of the cells + \param cellRows + number of rows of the grid + \param cellColumns + number of columns of the grid + \param cellLevel + number of levels of the grid + \param timestep + size of the time step + \param cellDimension + number of the state variables of the cells + \param o + initial observer + */ + CellMonitor(Simulation& sim, const data::Label& l, unsigned variablesInCount, unsigned variablesOutCount, unsigned cellRows, unsigned cellColumns, unsigned cellLevel, double timestep, unsigned cellDimension, ProcessObserver* o = 0); + + /** \brief Construction used with configuration file + \param sim + reference to one simulation-object + \param l + label of this object + \param fileName + name of the configuration file which contains settings like grid size of the cellular automaton + \param o + initial observer + */ + CellMonitor(Simulation& sim, const data::Label& l, const char*const configFileName, ProcessObserver* o = 0); + + /** \brief Construction used with configuration file + \param sim + reference to one simulation-object + \param l + label of this object + \param configFileName + name of the configuration file which contains settings like grid size of the cellular automaton + \param startDataFileName + name of the configuration file which contains settings like the start values or individual neighborhood settings of all cells + \param o + initial observer + */ + CellMonitor(Simulation& sim, const data::Label& l, const char*const configFileName, const char*const startDataFileName, ProcessObserver* o = 0); + + /// destruction + ~CellMonitor(); + + /** \brief Calculating the evolution of the cellular automaton. + \note This will be called by the Simulation-object. + */ + int main(); + + /** \brief Sets the time limit when the monitor has to finish the main method. + \param time + time to stop monitor + */ + void setTimeLimit(SimTime time); + + /** \brief Returns the time limit. + */ + SimTime getTimeLimit(); + + /** \brief Sets one transition object to all Cell-objects. + */ + void setTransitionToCells(Transition* transition); + + /** \brief Function for printing values. + */ + double* getValues(); + + /** \brief Returns the number of rows that belong to the grid of the cellular automaton. + */ + unsigned getRowCount(); + + /** \brief Returns the number of columns that belong to the grid of the cellular automaton. + */ + unsigned getColumnCount(); + + /** \brief Returns the number of levels that belong to the grid of the cellular automaton. + */ + unsigned getLevelCount(); + + /** \brief Adds one cell with given coordinates (row, column, level) to the boundary. + \param row + row that belongs to the cell + \param column + column that belongs to the cell + \param level + level that belongs to the cell + */ + void setIsBoundaryCell(unsigned row, unsigned column, unsigned level); + + /** \brief Sets the state value of one cell with given coordinates (row, column, level). + \param row + row that belongs to the cell + \param column + column that belongs to the cell + \param level + level that belongs to the cell + \param variableIndex + index of the variable with a range of 0 to dimension-1 + \param value + the value to be set + */ + void setCellValue(unsigned row, unsigned column, unsigned level, unsigned variableIndex, double value); + + /** \brief Returns the output value of one cell with given coordinates (row, column, level) and given variable index. + \param row + row that belongs to the cell + \param column + column that belongs to the cell + \param level + level that belongs to the cell + \param variableIndex + index of the variable with a range of 0 to dimension-1 + */ + double getCellValue(unsigned row, unsigned column, unsigned level, unsigned variableIndex); + + /** \brief Returns the global neighborhood type. + \note If different cells have different neighborhood types don't use this function. + */ + unsigned getNeighborhoodType(); + + /** \brief Returns the radius of the neighborhood. + \note If different cells have different neighborhood radiuses don't use this function. + */ + unsigned getNeighborhoodRadius(); + + /** \brief Returns a pointer to one cell-object with given coordinates (row, column, level). + \param row + row that belongs to the cell + \param column + column that belongs to the cell + \param level + level that belongs to the cell + */ + Cell* getCell(unsigned row, unsigned column = 0, unsigned level = 0); + + private: + /** \brief Returns a pointer to one cell with given index in the cell vector. + \param cellIndex + index of one cell in the cell vector (cellIndex = cellRows * (cellColumns * level + column) + row) + + \note This method is for internal use only. + */ + Cell* getCell_(unsigned cellIndex); + + /** \brief Sets the settings for the neighborhood. + \param neighborhoodType + type of the neighborhood + \param radius + radius of the neighborhood (1,....) + + \note For possible values of neighborhoodType take a look in CellMonitor.h + The default values are neighborhoodType = MOORE and radius = 1. + */ + void setNeighborhoodSettings(unsigned neighborhoodType, unsigned radius); + + /** \brief Sets parameters used by CellMonitor to create the cellular automaton with given file name. + \param fileName + name or rather path of the configuration file + */ + void setParameterFromConfigFile(const std::string fileName = "cellmonitor_config.xml"); + + /** \brief Sets parameters of the cellular automaton like start values and neighborhood settings with given file name. + \param fileName + name or rather path of the configuration file + */ + void setStartDataFromConfigFile(std::string fileName = "ca_start_data.xml"); + + /** \brief Creates a cellular automaton with the given numbers of rows, columns and levels. + \param rows + number of rows that belong to the grid of the cellular automaton + \param columns + number of columns that belong to the grid of the cellular automaton + \param level + number of levels that belong to the grid of the cellular automaton + + TODO cellDimension entfernen!!!! + */ + void generateCellularAutomaton(unsigned rows, unsigned columns, unsigned level, unsigned cellDimension); + + /** \brief Calculates the neighborhood of all cells. + */ + void calculateNeighboorhood(); + + private: + /** \brief This structure saves the settings for the global neighborhood. + \param + radius of the neighborhood (1,....) + \param neighborhoodType + type of the neighborhood + + \note For possible values of neighborhoodType take a look in CellMonitor.h + The default values are neighborhoodType = MOORE and radius = 1. + */ + struct neighborhoodSettings + { + unsigned neighborhoodType; + unsigned radius; + } typeOfNeighborhood; + + // Number of input, output and state variables which belong to a cell of the cellular automaton, stored in the values arrays. + unsigned cellDimension; + unsigned variablesInCount; + unsigned variablesOutCount; + + // Number of rows, columns and levels that belong to the grid of the cellular automaton. + unsigned cellRows; + unsigned cellColumns; + unsigned cellLevel; + + // Variables container used by CellMonitor for managing variables of the cells. + CellVariablesContainer* cellVariablesContainer; + + // Vector of all cell objects. + std::vector<Cell*> cellVector; + + // Size of every time step. + double timestep; + + // The time limit. + SimTime timeLimit; + + /** \brief Triggers the observer to write the input, output and state variables. + */ + void notifyValidState(); + + friend class Cell; + + friend class CellMonitorTrace; + }; + + //forward declaration + class CellPosition; + + /** \interface CellMonitorObserver + + \author Sascha Qualitz + + \brief Observer for CellMonitor specific events + + \since 3.0 + */ + class CellMonitorObserver: + public ProcessObserver + { + public: + // destruction + virtual ~CellMonitorObserver(){}; + +// virtual void onCreate( CellMonitor* sender ){} ///< Construction + + virtual void onNewValidState( CellMonitor* sender ){} ///< New valid state + + virtual void onBeginCalcStateChanges( CellMonitor* sender ){} ///< Monitor calculates the state changes + virtual void onEndCalcStateChanges( CellMonitor* sender ){} ///< Monitor ended one calculation step + + virtual void onSetTimeLimit(CellMonitor* sender, SimTime time){} ///< time changed + + virtual void onSetTransitionToCells(CellMonitor* sender){} ///< one transition was set to all cells + virtual void onSetNeighborhoodSettings(CellMonitor* sender, unsigned neighborhoodType, unsigned radius){} ///< neighborhood settings + virtual void onSetNeighborhoodType(CellMonitor* sender, unsigned neighborhoodType, CellPosition* position){} ///< neighborhood type + virtual void onSetNeighborhoodRadius(CellMonitor* sender, unsigned neighborhoodRadius, CellPosition* position){} ///< neighborhood radius + + virtual void onGenerateCellularAutomaton(CellMonitor* sender){} ///< generate cellular automaton + virtual void onCalculateNeighboorhood(CellMonitor* sender){} ///< calculate neighborhood + }; + + /** \class CellMonitorTrace + + \author Sascha Qualitz + + \brief Trace for cell state changes of the cellular automaton controlled by the monitor. + + \sa Cell, CellMonitorObserver, CellMonitor + + %CellMonitorTrace logs the state changes of the cells in the cellular automaton + into a xml file. The xml file is automatically opened and closed. + + \since 3.0 + */ + class CellMonitorTrace + : public CellMonitorObserver + { + public: + /// Construction + CellMonitorTrace( CellMonitor* cellMonitor = 0, const std::string& fileName = "" ); + /// Destruction + virtual ~CellMonitorTrace(); + + /// Follow state changes + virtual void onNewValidState( CellMonitor* sender ); + + private: + // Implementation + std::ostream* out; + bool firstTime; + const std::string& fileName; + + CellMonitor* cellMonitor; + + void openFile( const std::string& fileName ); + }; + + } +} +} + +#endif + diff --git a/odemx-lite/include/odemx/base/cellular_automaton/CellVariablesContainer.h b/odemx-lite/include/odemx/base/cellular_automaton/CellVariablesContainer.h new file mode 100644 index 0000000000000000000000000000000000000000..daf6b9b623513f257964b49bb313d4ebe43e05c0 --- /dev/null +++ b/odemx-lite/include/odemx/base/cellular_automaton/CellVariablesContainer.h @@ -0,0 +1,163 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file CellVariablesContainer.h + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Declaration of CellVariablesContainer + + \since 3.0 + */ + +#ifndef ODEMX_CELLVARIABLESCONTAINER_INCLUDED +#define ODEMX_CELLVARIABLESCONTAINER_INCLUDED + +namespace odemx { + namespace base { + namespace cellular { + + /** \class CellVariablesContainer + + \ingroup base + + \brief Abstract class for implementing memory handling of the cells in a cellular automaton. + + \sa Cell, CellMonitor, Transition + + \since 3.0 + */ + class CellVariablesContainer { + private: + /** \brief Construction + \param cellRows + number of rows that belong to the grid of the cellular automaton + \param cellColumns + number of columns that belong to the grid of the cellular automaton + \param cellLevel + number of levels that belong to the grid of the cellular automaton + \param variablesInCount + number of the input variables of the cells + \param variablesOutCount + number of the output variables of the cells + \param cellDimension + number of the state variables of the cells + */ + CellVariablesContainer(unsigned cellRows, unsigned cellColumns, unsigned cellLevel, unsigned variablesInCount, unsigned variablesOutCount, unsigned cellDimension); + + /// destruction + virtual ~CellVariablesContainer(); + + /** \brief Sets output value of one variable. + \param baseIndex + base index for variables of cell objects + \param variableIndex + index of the variable to be set to the \p value + \param value + the value to be set + */ + virtual void setOutputValue(unsigned baseIndex, unsigned variableIndex, double value); + + /** \brief Sets state value of one variable. + \param baseIndex + base index for variables of cell objects + \param variableIndex + index of the variable to be set to the \p value + \param value + the value to be set + */ + virtual void setStateValue(unsigned baseIndex, unsigned variableIndex, double value); + + /** \brief Sets input value of one variable. + \param baseIndex + base index for variables of cell objects + \param variableIndex + index of the variable to be set to the \p value + \param value + the value to be set + */ + virtual void setInputValue(unsigned baseIndex, unsigned variableIndex, double value); + + /** \brief Returns output value of one variable. + \param baseIndex + base index for variables of cell objects + \param variableIndex + index of the returned variable + */ + virtual double getOutputValue(unsigned baseIndex, unsigned variableIndex); + + /** \brief Returns state value of one variable. + \param baseIndex + base index for variables of cell objects + \param variableIndex + index of the returned variable + */ + virtual double getStateValue(unsigned baseIndex, unsigned variablesIndex); + + /** \brief Returns input value of one variable. + \param baseIndex + base index for variables of cell objects + \param variableIndex + index of the returned variable + */ + virtual double getInputValue(unsigned baseIndex, unsigned variableIndex); + + /** \brief Returns the number of rows that belong to the grid of the cellular automaton. + */ + unsigned getNumberOfRows(); + + /** \brief Returns the number of columns that belong to the grid of the cellular automaton. + */ + unsigned getNumberOfColumns(); + + /** \brief Returns the number of level that belong to the grid of the cellular automaton. + */ + unsigned getNumberOfLevels(); + + /** + * \brief Function for printing values. + */ + double* getOutputValues(); + + private: + // Number of rows, columns and levels that belong to the grid of the cellular automaton. + unsigned cellRows; + unsigned cellColumns; + unsigned cellLevel; + + // Number of input, output and state variables which belong to a cell of the cellular automaton, stored in the values arrays. + unsigned variablesInCount; + unsigned variablesOutCount; + unsigned cellDimension; + + // Arrays which stores the input, output and state variables which belong to a cell of the cellular automaton. + double* input_values; + double* state_values; + double* output_values; + + friend class CellMonitor; + + friend class Cell; + }; + + } +} +} +#endif diff --git a/odemx-lite/include/odemx/base/cellular_automaton/Transition.h b/odemx-lite/include/odemx/base/cellular_automaton/Transition.h new file mode 100644 index 0000000000000000000000000000000000000000..914b79a44890d9f4df6b2f72645a860bbf7f595b --- /dev/null +++ b/odemx-lite/include/odemx/base/cellular_automaton/Transition.h @@ -0,0 +1,164 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Transition.h + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Abstract class to derive a representation of one transition of a cell in the cellular automaton. + \sa Cell, CellMonitor + \since 3.0 + */ + +#ifndef ODEMX_TRANSITION_INCLUDED +#define ODEMX_TRANSITION_INCLUDED + +#include <string> +#include <exception> +#include <map> +#include <odemx/base/SimTime.h> +#include <odemx/base/TypeDefs.h> +#include <odemx/base/cellular_automaton/Cell.h> + +using namespace odemx::base; + +namespace odemx { + namespace base { + namespace cellular { + + //forward declaration + class CellMonitor; + + class Cell; + + struct typeOfNeighborhood; + + /** \class NotAssignedException + + \ingroup base + + \author Sascha Qualitz + + \brief Exception for methods which fails, because there is missingObject assigned for this object + + \since 3.0 + */ + class NotAssignedException : public std::exception { + public: + /// Constructor + NotAssignedException(const char* missingObject, const char* object); + + /// Destructor + ~NotAssignedException() throw(); + + /// give message for exception + const char* what() const throw(); + + private: + std::string msg; //saves the Exception message + }; + + /** \class Transition + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling a transition function + + %Transition is a base class for all user defined transition functions. + It provides the functionality to compute state changes for one cell. + In addition one can define an output function here. It configures which + state variables other cells can use to compute their state changes. + + \sa CellMonitor, Cell + + \since 3.0 + */ + class Transition + { + public: + /** \brief Construction + */ + Transition(); + + /// destruction + virtual ~Transition(); + protected: + /** \brief Calculates the transition function based on the own values and influences of other cells. + \param time + time + */ + virtual void transitionFunction(SimTime time) = 0; + + /** \brief Configures which state variables other cells can use to compute their state changes. + \note Optional one can rewrite this method. Default of this method is copying the state values to the output array. + */ + virtual void outputFunction(); + + /** \brief Calculates an user-defined neighborhood. + \param radius + radius of the neighborhood + */ + virtual std::map<CellPosition, Cell*, ComparePositions> calculateAlternativeNeighborhood(unsigned radius = 1); + + /** \brief Sets the cell-object. + \param cell + the cell to set + */ + void setCell(Cell* cell); + + /** \brief Returns state variable of the cell belonging to this transition object. + \param variableIndex + index of the variable to get \p value + */ + double getValue(unsigned variableIndex = 0); + + /** \brief Sets value of one variable of the cell belonging to the transition object + \param variableIndex + index of the variable to be set to the \p value + \param value + the value to be set + */ + void setValue(unsigned variableIndex, double value); + + /** \brief Returns a cell-object-pointer if the cell with given position is in the neighborhood. Otherwise it returns 0. + \param row + row-position of the cell + \param column + column-position of the cell + \param level + level-position of the cell + */ + Cell* searchNeighbor(unsigned row, unsigned column = 0, unsigned level = 0); + + protected: + + // Cell-object, where the transition function belongs to. + Cell* cell; + + friend class Cell; + + friend class CellMonitor; + }; + } + } +} +#endif diff --git a/odemx-lite/include/odemx/base/continuous/Continuous.h b/odemx-lite/include/odemx/base/continuous/Continuous.h new file mode 100644 index 0000000000000000000000000000000000000000..fbb4ac8481387dc3186319c5373820f389b83658 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/Continuous.h @@ -0,0 +1,410 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004, 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Continuous.h + + \author Michael Fiedler + + \date created at 2008/11/21 + + \brief Declaration of odemx::base::Continuous + + \sa Continuous.cpp + + \since 3.0 + */ + +#ifndef ODEMX_CONTINUOUS_INCLUDED +#define ODEMX_CONTINUOUS_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/ODEObject.h> +#include <odemx/base/continuous/VariableContainer.h> +#include <odemx/data/Producer.h> +#include <odemx/data/Observable.h> + +#include <string> +#include <vector> +#include <list> + +namespace odemx { + namespace base { + namespace continuous { + + // forward declarations + class Monitor; + + class ODEObject; + + class VariableContainer; + + class ContinuousObserver; + + /** \class Continuous + + \ingroup base + + \author Michael Fiedler + + \brief %Continuous is the class for describing values of a continuous process in the system + + \note since 3.0 the values and the equations of a continuous process are split in Continuous and ODEObject + + \note Continuous supports Observation + + \note Continuous supports Trace + + \note Continuous supports Logging + + \sa ODEObject, Monitor, StateEvent, ODESolver + + The user creates an %Continuous instance for each continuous object in a simulation. + This instance holds dimension continuous values. + + \since 3.0 + + */ + class Continuous : public data::Producer, public data::Observable<ContinuousObserver> { + public: + /** \brief Construction + \param sim reference to one simulation-object + \param l label of this object + \param dimension count of continuous values for the instance (dedicated) + */ + Continuous(Simulation& sim, const data::Label& label, int dimension); + + /** \brief Construction + \param sim reference to one simulation-object + \param l label of this object + \param monitor the monitor were the continuous object belongs to + \param dimension number of continuous values for the instance (dedicaated) + \param equation first equation in the life cycle of the object this can changed and other equations can be added via addODE(...). + */ + Continuous(Simulation& sim, const data::Label& label, Monitor* monitor, int dimension, ODEObject* equation = 0); + + /** \brief Construction + \param sim reference to one simulation-object + \param l label of this object + \param monitor the monitor were the continuous object belongs to + \param dimension number of continuous values for the instance (dedicaated) + \param equationList list of equations of the continuous object this can changed and other equations can be added via addODE(...). + */ + Continuous(Simulation& sim, const data::Label& label, Monitor* monitor, int dimension, std::list<ODEObject*> equationList); + + /// Destruction + ~Continuous(); + + /** \name Equation handling + + These functions manage which equations are currently influencing the continuous values. + + @{ + */ + /** \brief Adds an equation + \param equation + pointer to an ODEObject describing an equation on the values + \note All equations which are added will be used for integration simultaneously and summed up. + \note This results in a change of the associated monitor. + */ + void addODE(ODEObject *equation); + + /** \brief Adds a list of equations + \param equation + list of pointer to an ODEObject describing the equations on the values + \note All equations which are added will be used for integration simultaneously and summed up. + \note This results in a change of the associated monitor. + */ + void addODEList(std::list<ODEObject*> equation); + + /** \brief Remove an equation + \param + pointer to the ODEObject to be removed + \note The equation is only removed from calculation. The object will not be destroyed. + \note This results in a change of the associated monitor. + */ + void removeODE(ODEObject *equation); + + //@} + + /** \name Monitor handling + + These functions are setting and returning the %Monitor, which calculates the evolution of the + continuous values of this instance described by the added equations. + + @{ + */ + /** \brief Sets the Monitor in which the Continuous %Process will be integrated + \param monitor + pointer to the monitor which manages this instance + \note The instance will automatically be transferred from another %Monitor, if one was assigned. + \note To remove the Continuous object from a %Monitor pass NULL as parameter. + \note This results in a change to the involved monitors. + */ + void setMonitor(Monitor *monitor); + + /** \brief Returns the Monitor which manages this instance + */ + Monitor* getMonitor(); + //@} + + /** \brief Returns the dimension of the Continuous %Process + + \note That means the number of variables the %Process has. + */ + int getDimension(); + + /** \name Access to values during integration + + Values should only be changed, when the responsible Monitor is not integrating. + + @{ + */ + /** \brief Sets the value of one variable + \param i + index of the variable to be set (range 0..(Dimension-1)) + \param value + the value which the variable will be set to + \note Should only be used, when responsible %Monitor is not running (that means is not integrating). + \note This results in a change of the associated monitor. + */ + void setValue(int i, double value); + + /** \brief Returns the value of one variable + \param i + index of the returned variable (range 0..(Dimension-1)) + \note Should only be used when responsible %Monitor is not running (that means is not integrating) + \return the value of the variable accessed by index \p i + */ + double getValue(int i); + //@} + + /** \name Access to Values in Integration + + These functions are for the evaluation of the differential equations. + That means they are used in implementations of the functions derivates and jacobi of the class ODEObject. + The user has to use the member function getValueForDerivative to access the value of one variable in such a implementation. + + \note These functions should only be used while integration. + + @{ + */ + /** \brief Returns the value of one variable while integrating + \param i + index of the returned variable (range 0..(Dimension-1)) + \return the value of the i-th variable at a possible intermediate step + + \note The user has to use this function to access the value of a variable in an implementation of derivates or + jacobi in a derived class of ODEObject + */ + double getValueForDerivative(int i); + + /** \brief Sets the value for y' = f(y) in the i-th component + \param i + index of the variable to be set (range 0..(Dimension-1)) + \param value + set y'[i] = \p value + + \note The values of multiple calls will be summed up. + */ + void setDerivative(int i, double value); + + /** \brief Returns the value of y' = f(y) in the i-th component + \param i + index of the variable to get (range 0..(Dimension-1)) + + \note That means y'[i] will be returned + */ + double getDerivative(int i); + + /** \brief Sets the value for Df exactly f_i \partial y[j] = value + \param i + index of the component to differentiate (range 0..(Dimension-1)) + \param j + index of the variable by which will be differentiated (range 0..(Dimension-1)) + + For an equation given as y' = f(y) set the result \p value for differentiating + the i-th component of f by the j-th component of y. + + \note The values of multiple calls will be summed up. + */ + void setJacobi(int i, int j, double value); + + /** \brief Sets the value for Df exactly f_i \partial continuous->y[j] = value + \param i + index of the component to differentiate (range 0..(Dimension-1)) + \param continuous + pointer to a continuous instance which influences the right hand side + \param j + index of the variable by which will be differentiated (range 0..(continuous->getDimension()-1)) + + For an equation given as y' = f(y, x) set the result \p value for differentiating + the i-th component of f by the j-th component of x. + + \note The values of multiple calls will be summed up. + \note To work correctly this instance and \p continuous have to be managed by the same %Monitor + */ + void setJacobi(int i, Continuous* continuous, int j, double value); + + /** \brief Returns the value of Df returns f_i \partial y[j] + \param i + index of the component to get (range 0..(Dimension-1)) + \param j + index of the variable by which will be differentiated (range 0..(Dimension-1)) + + For an equation given as y' = f(y) gives the intermediate result for differentiating + the i-th component of f by the j-th component of y. The value of result is determined + by previous calls to setJacobi. + */ + double getJacobi(int i, int j); + + /** \brief Returns the value of Df returns f_i \partial continuous->y[j] + \param i + index of the component to differentiate (range 0..(Dimension-1)) + \param continuous + pointer to a Continuous instance which influences the right hand side + \param j + index of the variable by which will be differentiated (range 0..(continuous->getDimension()-1)) + + For an equation given as y' = f(y, x) set the result \p value for differentiating + the i-th component of f by the j-th component of x. The value of result is determined + by previous calls to setJacobi. + + \note To work correctly this instance and \p continuous have to be managed by the same %Monitor. + */ + double getJacobi(int i, Continuous* continuous, int j); + + /** \brief Sets the value for DfDt exactly f_i \partial t = value + \param i + index of the component to set (range 0..(Dimension-1)) + + For an equation given as y' = f(y) set the result \p value for differentiating + the i-th component of f by time. + + \note The values of multiple calls will be summed up. + */ + void setDfDt(int i, double value); + + /** \brief gets the value for DfDt returns f_i \partial t = value + \param i + index of the component to get (range 0..(Dimension-1)) + + For an equation given as y' = f(y) set the result \p value for differentiating + the i-th component of f by time. The value of result is determined + by previous calls to setDfDt. + */ + double getDfDt(int i); + //@} + + /** \brief Sets changed on true, so that the monitor will call solver->init() before next calculation + */ + void setChanged(); + + /** \brief Triggers the observer to write the state variables + */ + void notifyValidState(); + + private: + // List all equations which belong to this instance + std::list<ODEObject*> equations; + + // Monitor in which this instance will be integrated + Monitor *monitor; + + // Dimension of the instance + int dimension; + + // Base index for variables of this continuous object in the variables container of the monitor + int baseIndex; + + friend class Monitor; + }; + + //forward declaration + class Monitor; + + /** \interface ContinuousObserver + + \author Sascha Qualitz + + \brief Observer for Continuous specific events + + \sa Monitor + + \since 3.0 + */ + class ContinuousObserver: + public ProcessObserver + { + public: + virtual void onCreate( Continuous* sender ) {} ///< Construction + + virtual void onNewValidState( Continuous* sender ) {} ///< New valid state + + virtual void onSetMonitor( Continuous* sender, Monitor* monitor ) {} ///< new Monitor set + + virtual void onAddODE(Continuous* sender, ODEObject* ode) {} ///< new ordinary differential equation added + virtual void onRemoveODE(Continuous* sender, ODEObject* ode) {} ///< old ordinary differential equation removed + }; + + /** \class ContinuousTrace + + \author Sascha Qualitz + + \brief Trace for Continuous state changes of continuous objects controlled by the monitor + + \sa Continuous MonitorObserver + + ContinuousTrace logs the state changes of the Continuous objects + into a text file. The text file is automatically opened and closed. + + \since 3.0 + */ + class ContinuousTrace + : public ContinuousObserver + { + public: + /// Construction + ContinuousTrace( Continuous* contu = 0, const std::string& fileName = "" ); + /// Destruction + virtual ~ContinuousTrace(); + + /// Follow state changes + virtual void onNewValidState( Continuous* sender ); + + private: + // Implementation + std::ostream* out; + bool firstTime; + const std::string& fileName; + + Continuous* continuous; + + void openFile( const std::string& fileName ); + }; + } + } +} +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_CONTINUOUS_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/DfDt.h b/odemx-lite/include/odemx/base/continuous/DfDt.h new file mode 100644 index 0000000000000000000000000000000000000000..25f7c8d76bc22621d333f10265ea2439519d9c75 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/DfDt.h @@ -0,0 +1,150 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file DfDt.h + + \author Sascha Qualitz + + \date created at 2009/10/26 + + \brief Declaration of class DfDt + + \since 3.0 + */ + +#ifndef ODEMX_DFDT_INCLUDED +#define ODEMX_DFDT_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +namespace odemx { + namespace base { + namespace continuous { + + //Forward declaration + class Continuous; + + class ODEObject; + + /** \class DfDt + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling a derived by time equation-element in the class ODEObject + Used in the jacobi function in a derived class of ODEObject. + + To describe ordinary derived by time equations the user has to use this class. + + \sa JacobiMatrix + \sa State + \sa Rate + */ + class DfDt { + public: + /** + \brief Construction + \param continuous + pointer to the continuous object where the dfdt-element belongs to + + \note The variables continuous and index_ will be set to 0 + */ + DfDt(); + + /** + \brief Construction + \param continuous + pointer to the continuous object where the dfdt-element belongs to + + \note The variable index_ will be set to 0 + */ + DfDt(Continuous* continuous); + + /// destruction + virtual ~DfDt(); + + /** + \brief Overrides the converting operator double to convert implicit an object of type DfDt to double + + \note If this operator is called, the double value is the value that is returned by the method + getDfDt(index_) of the corresponding continuous-object. The variable index_ is set to an index + between 0 and continuous->getDimension before. To set the variables index_ see also the methods + operator []. + */ + operator double() { + return this->getValue(); + } + + /** + \brief Overrides the assignment operator to store the value of type double in the variable container + \param value + value to be set + */ + DfDt& operator =(const double value); + + /** + \brief Overrides the index operator to set the internal variable index_ + \param index + index of the variable to get/set (range 0..(Dimension-1)) + */ + DfDt& operator [](const unsigned i); + + /** + \brief Sets the variable continuous + \param continuous + pointer to the continuous object where the equation-element belongs to + */ + void setContinuous(Continuous* continuous); + + private: + + /** + \brief Returns the value of the dfdt-element with given index index_ + + getValue returns the value from the correct index position, because index_ was set by the overwritten operator[] before. + */ + double getValue() const; + + /** + \brief Sets the value of type double at the index index_ + \param value + value to be set + + \note setValue stores the value at the correct index, because index_ was set by the overwritten operator[] before. + */ + void setValue(double value); + + // pointer to the continuous object where the dfdt-element belongs to + Continuous* continuous; + + // index of the variable to get/set (range 0..(Dimension-1)) + unsigned index_; + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_DFDT_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/JacobiMatrix.h b/odemx-lite/include/odemx/base/continuous/JacobiMatrix.h new file mode 100644 index 0000000000000000000000000000000000000000..a8031a90ef85010bf4b41b6fefbb967342cfd512 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/JacobiMatrix.h @@ -0,0 +1,164 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** \file JacobiMatrix.h + + \author Sascha Qualitz + + \date created at 2010/2/26 + + \brief Declaration of class odemx::base::continuous::JacobiMatrix + + \sa JacobiMatrix.cpp + + \since 3.0 + */ + +#ifndef ODEMX_JACOBIMATRIX_INCLUDED +#define ODEMX_JACOBIMATRIX_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +namespace odemx { + namespace base { + namespace continuous { + + //Forward declaration + class Continuous; + + class ODEObject; + /** \class JacobiMatrix + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling the jacobi-matrix in the class ODEObject. + + To describe the jacobi-matrix of ordinary differential equations the user has to use this class. + Used in the jacobi function in a derived class of ODEObject. + + \sa Rate + \sa State + \sa DfDt + */ + + class JacobiMatrix { + public: + /** + \brief Construction + + \note The variables continuous, otherContinuous, row_ and column_ will be set to 0. + */ + JacobiMatrix(); + + /** + \brief Construction + \param continuous + pointer to the continuous object where the jacobi-matrix belongs to + + \note The variables row_, column_ and otherContinuous will be set to 0. + */ + JacobiMatrix(Continuous* continuous); + + /** + \brief Construction + \param continuous + pointer to the continuous object where the jacobi-matrix belongs to + \param otherContinuous + pointer to a continuous instance which influences the right hand side of the equation + + \note The variables row_ and column_ will be set to 0 + */ + JacobiMatrix(Continuous* continuous, Continuous* otherContinuous); + + /// destruction + ~JacobiMatrix(); + + /** + \brief Overrides the assignment operator to store the value of type double in the variable container. + \param value + value to be set + */ + JacobiMatrix& operator =(const double value); + + /** + \brief Overrides the ()-operator to set the values of row_ and column_. + \param row + row number of the matrix + \param column + column number of the matrix + */ + JacobiMatrix& operator ()(const unsigned row, const unsigned column); + + /** + \brief Sets the continuous variable + \param continuous + pointer to the continuous object where the jacobi-matrix belongs to + */ + void setContinuous(Continuous* continuous); + + /** + \brief Sets the variables continuous and otherContinuous + \param continuous + pointer to the continuous object where the jacobi-matrix belongs to + \param otherContinuous + pointer to a continuous instance which influences the right hand side of the equation + */ + void setContinuous(Continuous* continuous, Continuous* otherContinuous); + + private: + /** + \brief Returns value of the jacobi-matrix, at the given indexes row_ and column_ + + getValue returns the correct value, because row_ and column_ was set by the overwritten ()-operator before. + */ + double getValue() const; + + /** + \brief Sets the value of the jacobi-matrix at the indexes row_ and column_ + \param value + value to be set + */ + void setValue(double value); + + // pointer to the continuous object where the jacobi-matrix belongs to + Continuous* continuous; + + // pointer to a continuous instance which influences the right hand side of the equation + Continuous* otherContinuous; + + // row number of the matrix + unsigned row_; + + // column number of the matrix + unsigned column_; + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif/* ODEMX_JACOBIMATRIX_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/Monitor.h b/odemx-lite/include/odemx/base/continuous/Monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..af4c12b73d4322313978c20781c1a018592a02bd --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/Monitor.h @@ -0,0 +1,444 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Monitor.h + + \author Michael Fiedler + + \date created at 2008/11/21 + + \brief Declaration of Monitor + + \since 3.0 + */ + +#ifndef ODEMX_MONITOR_INCLUDED +#define ODEMX_MONITOR_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/Process.h> +#include <odemx/base/continuous/ODESolver.h> +#include <odemx/base/continuous/Continuous.h> +#include <odemx/base/continuous/StateEvent.h> +#include <odemx/base/continuous/VariableContainer.h> +#include <list> +#include <fstream> +#include <iostream> +#include <odemx/setup.h> +#include <odemx/data/Observable.h> + +namespace odemx { + namespace base { + namespace continuous { + + /** Choice if integration is done by interval or by steps + */ + enum WorkingModes { + stepwise, intervall + }; + + /** Choice how to search for StateEvents. That means if to work on a linear approximation or + direct on the solution. + */ + enum SearchModes { + linearization, direct + }; + + //forward declaration + class ODESolver; + + class VariableContainer; + + class Continuous; + + class StateEvent; + + class MonitorObserver; + + /** \class Monitor + + \ingroup base + + \brief A monitor is used to integrate several continuous processes simultaneously, + but independent from continuous processes in other monitors of the simulation. + + \sa Continuous, ODEObject, ODESolver, StateEvent, Process + + \since 3.0 + */ + class Monitor : public Process, public data::Observable<MonitorObserver> { + public: + + /** \brief Construction + \param variablesArraySize + initial size of data structs + \param s + pointer to the Simulation object + \param label + label of this object + \param solver + the solver for this monitor + \param o + initial observer + \note If the data structs are to small on runtime, they will be enlarged automatically at cost of speed + */ + Monitor(Simulation& s, const data::Label& label, int variablesArraySize, ODESolver* solver, MonitorObserver* o = 0); + + /// destruction + ~Monitor(); + + /** \brief sets how monitor schedules integration + \param mode + If value is 'stepwise' the %Monitor will be scheduled after every step (as in older version). + If value is 'interval' the %Monitor will be scheduled only on known synchronization points. + + \note The synchronization point is the earliest time to which one of the processes in the list wait list is scheduled. + */ + void setWorkingMode(WorkingModes mode); + + /** \brief Sets the method how to search for StateEvents + \param mode + value is direct or linearization + + Sets if monitor searches for StateEvents directly on the solution (slower but more accurate) or + on a linearization (faster) + */ + void setSearchMode(SearchModes mode); + + /** \brief Synchronizes this instance to another monitor + + That means the other monitor will be synchronized to the time of this monitor + + \note not implemented now + */ + void synchronizeToMonitor(Monitor *otherMonitor); + + /** \name handle used solver + + These functions are to control which solving method is used for integration + + @{ + */ + /** \brief Sets the solver for this monitor + */ + void setODESolver(ODESolver *solver); + + /** \brief Returns the actual solver of this monitor + */ + ODESolver* getODESolver(); + //@} + + /** \name Process synchronization + + These functions control with which processes the monitor synchronizes. + This means the monitor stops integration at times when one of these processes is scheduled. + The integration will be continued after this process has been executed. + + \note This is necessary for time consistent exchange of values between processes and monitors. + + @{ + */ + /** \brief Adds a discrete process to which the monitor will be synchronized + + That means the monitor will only integrate to the next event of one discrete process. + The monitor waits till this event is computed. + */ + void addProcessToWaitList(Process *process); + + /** \brief Removes a discrete process from the monitor to synchronize + */ + void removeProcessFromWaitList(Process *process); + //@} + + /** \name continuous processes and StateEvents + + This functions control which continuous processes are calculated by this monitor and + which StateEvents will be checked during integration. + + @{ + */ + /** \brief Adds a continuous process to the monitor + + This process will be integrated by the monitor simultaneously + to other continuous processes of the monitor. + + \note This results in a change of the monitor. + */ + void addContinuous(Continuous *continuous); + + /** \brief Removes a continuous process from the monitor + + \note This results in a change of the monitor. + */ + void removeContinuous(Continuous *continuous); + + /** \brief Adds a StateEvent to the monitor to watch for + + That means after every step the monitor checks for all StateEvents. + If condition() of one StateEvent evaluates to true the point of switching + from false to true will be approximated and at this point action of the StateEvent + will be executed. The StateEvent will be removed from the monitor afterwards + + \note If condition() evaluates to true while added, then action() is immediately called. + */ + void addStateEvent(StateEvent *stateEvent); + + /** \brief Removes a StateEvent from the monitor + */ + void removeStateEvent(StateEvent *stateEvent); + //@} + + /** \brief Calculates the evolution of the continuous processes + + \note This will be called by Simulation. + */ + int main(); + + /** \name stop monitor + + These functions are to set the time limit for the main method to work or give a stop command. + + \note The monitor will only integrate, if there is a time limit set or processes to synchronize with or StateEvents to check. + \note If there are only StateEvents to check be sure that at least one will evaluate at some point to true or you will have an infinite loop. + + @{ + */ + /** \brief Sets a time limit when the monitor will finish the main method + \param time + time to stop monitor + */ + void setTimeLimit(SimTime time); + + /** \brief Returns the time limit + \param time + the set time limit for this instance, which is only valid if returned true + */ + bool getTimeLimit(SimTime* time); + + /** \brief Remove time limit + */ + void removeTimeLimit(); + + /** \brief Returns the execution time of the next synchronized process + */ + SimTime getStepTimeLimit(); + + /** \brief Forces the monitor to finish the main method when next time limit is reached + */ + void stop(); + //@} + + /** \name internal Time + + To make ODEMx time representation independent of the time representation in the solver + (numerical framework) the monitor has an internal timing for conversion. + This means the monitor has an internal reference time and an actual time, + which is after the reference time. + + @{ + */ + /** \brief Sets internal reference time + \param time + the time limit to be set + + \note That means a change for the calculation and triggers a new initialization for the solver. + */ + void setInternalTime(SimTime time); + + /** \brief Returns internal reference time + */ + SimTime getInternalTime(); + + /** \brief Returns actual time of monitor + */ + SimTime getActualInternalTime(); + + /** \brief Sets internal reference time to actual time + + Sets internal reference time in a way that actual time and internal + reference time are equal for this monitor. + + \note That means a change for the calculation and triggers a new initialization for the solver + */ + void adaptInternalTime(); + //@} + + /** \brief Sets the monitor changed + + If the continuous system has a discrete change, the solver has to be newly initialized + to guarantee consistency. So it causes a call of solver->init() before next calculation. + + \note As long a user access only objects by supplied functions there is no need to call this. + */ + void setChanged(); + + protected: + + // the solver used by the monitor + ODESolver *solver; + + // the working mode in which the monitor runs + WorkingModes workingMode; + + // the search mode used by the monitor to search for the appearance of state events + SearchModes searchMode; + + // list of the discrete processes which the monitor synchronizes to + std::list<Process*> waitForProcesses; + + // list of the continuous processes managed by the monitor + std::list<Continuous*> continuousList; + + // list of the StateEvents the monitor watches for + std::list<StateEvent*> stateEvents; + + // actual size of the variable structs + int variablesArraySize; + + // actual number of variables used + int variablesCount; + + // variable container used by monitor for managing variables + VariableContainer *variables; + + // the internal reference time value + SimTime internalTime; + + // the time limit if set + SimTime timeLimit; + + // indicates if a time limit is set + bool timeLimitSet; + + // indicates if stop() was called + bool hasToStop; + + // actual time of monitor is internalTime + diffTime + double diffTime; + + // indicates if the system has changed since the calculation of the last step + bool changed; + + /** \brief Integration to \p time + \param time + the time limit to which will be integrated + + \note internal function + */ + void integrateUntil(SimTime time); + + /** \brief Integration till state event occurs + + \note internal function + */ + void integrate(); + + /** \brief Searches the time when a state event occurs. + When a known condition is false at internalTime + old_diffTime with values old_variable_values (for all + state events) and in the actual state there is a state event of the monitor with condition true, + then the monitor triggers this event (calls the method action()). + \param old_diffTime + initial left bound of the search interval + \param old_variable_values + initial values for the search + */ + void searchStateEvent(double old_diffTime, double *old_variable_values); + + /** \brief Evaluates all equations of all continuous processes as one function. + It will be evaluated as sum of partial functions at time internalTime + time. + \param time + the time limit + */ + void evalF(double time); + + /** \brief Evaluates all jacobian of all continuous processes as one matrix. + It will be evaluated as sum of partial matrices at time internalTime + time. + \param time + the time limit + */ + void evalJacobian(double time); + + friend class Continuous; + friend class ODESolver; + friend class MonitorTrace; + }; + + //forward declaration + class Monitor; + + class Continuous; + + /** \interface MonitorObserver + + \author Sascha Qualitz + + \brief Observer for monitor specific events + + \sa Continuous + + \since 3.0 + */ + class MonitorObserver: + public ProcessObserver + { + public: + virtual ~MonitorObserver(){}; + + virtual void onCreate( Monitor* sender ){} ///< Construction + + virtual void onAddProcessToWaitList( Monitor* sender, Process* peer ){} ///< Add peer + virtual void onRemoveProcessFromWaitList( Monitor* sender, Process* peer ){} ///< Remove peer + + virtual void onBeginIntegrate( Monitor* sender ){} ///< Begin integrate + virtual void onEndIntegrate( Monitor* sender){} ///< End integrate + + virtual void onBeginIntegrateUntil( Monitor* sender ){} ///< Begin integrate + virtual void onEndIntegrateUntil( Monitor* sender){} ///< End integrate + + virtual void onNewValidState( Monitor* sender ){} ///< New valid state + + virtual void onAddContinuous( Monitor* sender, Continuous* continuous ){} ///< new continuous object added + virtual void onRemoveContinuous( Monitor* sender, Continuous* continuous ){} ///< continuous object removed + + virtual void onAddStateEvent( Monitor* sender, StateEvent* event ){} ///< new state event added + virtual void onRemoveStateEvent( Monitor* sender, StateEvent* event ){} ///< state event removed + + virtual void onStop( Monitor* sender){} ///< Monitor stops + + virtual void onSetODESolver( Monitor* sender, ODESolver* solver){} ///< set ODESolver + + virtual void onSetChanged( Monitor* sender){} ///< system changed + + virtual void onSetInternalTime(Monitor* sender, SimTime time){} ///< internal time changed + + virtual void onAdaptInternalTime(Monitor* sender, SimTime time){} ///< adapted internal time + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_MONITOR_INCLUDED */ + diff --git a/odemx-lite/include/odemx/base/continuous/ODEObject.h b/odemx-lite/include/odemx/base/continuous/ODEObject.h new file mode 100644 index 0000000000000000000000000000000000000000..6f3cbb56197fee22621d69a3764eacca877d4228 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/ODEObject.h @@ -0,0 +1,189 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ODEObject.h + + \author Michael Fiedler + + \date created at 2008/11/21 + + \brief abstract class to derive a representation of an ordinary differential equation + \sa Continuous, Monitor, StateEvent + \since 3.0 + */ + +#ifndef ODEMX_ODEOBJECT_INCLUDED +#define ODEMX_ODEOBJECT_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/SimTime.h> + +#include <odemx/base/TypeDefs.h> + +#include <string> +#include <exception> +#include <vector> +#include <list> + + +namespace odemx { +namespace base { +namespace continuous { + +//class Monitor; //TODO: really useful? + +class Continuous; + + +/** Exception for methods which fails, because there is missingObject assigned for this object + */ +class NotAssignedException: public std::exception +{ +public: + /// Constructor + NotAssignedException(const char* missingObject, const char* object); + /// Destructor + ~NotAssignedException() throw(); + /// give message for exception + const char* what() const throw(); + +private: + // contains the Exception message + std::string msg; +}; + + +/** \class ODEObject + + \ingroup base + + \author Michael Fiedler + + \brief Object for handling an equation + + To describe an ordinary differential equation the user has to implement derivates and jacobi. + + \note In such implementations the user has to use getValueForDerivative to access the variables of + the corresponding Continuous instance. + */ +class ODEObject +{ +public: + /** \brief Construction + */ + ODEObject(const Derivative& derivatives, const Derivative& jacobi) :derivatives_{derivatives}, jacobi_{jacobi}, continuous{0} + {} + + /** \brief Construction + */ + ODEObject(Derivative&& derivatives, Derivative&& jacobi) :derivatives_{derivatives}, jacobi_{jacobi}, continuous{0} + {} + + /// destruction +// virtual ~ODEObject(); + + /** \name Handling of corresponding Continuous instance + + These are the functions to set/get the Continuous instance for this equation to work on. + If the user wants to have an equation which works on more than one Continuous instance he + has to extend this functionality for the extra instances. + + @{ + */ + /** \brief Adds this ODEObject-instance to a Continuous-Object + \param continuous + pointer to Continuous instance where this equation will be added + */ + void setContinuous(Continuous* continuous); //TODO: is never used! + + /** \brief Returns the corresponding Continuous instance + \note If no corresponding Continuous instance is set, the result will be NULL + */ + Continuous* getContinuous(); + //@} + + /** \brief implementation of equation in form y' = f(y) + + the following is an example for implementation of this function + + v'[0] = v[1] + + v'[1] = v[0] + + in code: + + DerivatesElement rate(continuous); + + DerivatesElement state(continuous); + + rate[0] = state[1]; + + rate[1] = -1 * state[0]; + + \sa Rate, State + */ + void derivates(SimTime time); + /** \brief derivates of implemented equation in form y' = f(y) + + the following is an example for implementation of this function (fßx means derive f by x): + + in code: + + JacobiElement jacobi(continuous); + + DfDtElement dfdt(continuous); + + jacobi(0,0) = 0; + + jacobi(0,1) = 1; + + jacobi(1,0) = -1; + + jacobi(1,1) = 0; + + dfdt[0] = 0; + + dfdt[1] = 0; + */ + void jacobi(SimTime time); + +// protected: +private: + // stores the Continuous-Object where equation belongs to + Continuous* continuous; + Derivative derivatives_; + Derivative jacobi_; + +// protected: +public: + friend class Continuous; // FIXME needed? + +}; +} +} +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_ODEOBJECT_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/ODESolver.h b/odemx-lite/include/odemx/base/continuous/ODESolver.h new file mode 100644 index 0000000000000000000000000000000000000000..1b587924ba101600f9897a77b6b8d10f59c785c6 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/ODESolver.h @@ -0,0 +1,227 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ODESolver.h + + \author Michael Fiedler + + \date created at 2008/11/21 + + \brief Declaration of ODESolver + + \since 3.0 + */ + +#ifndef ODEMX_ODESOLVER_INCLUDED +#define ODEMX_ODESOLVER_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/VariableContainer.h> +#include <odemx/data/Producer.h> +#include <odemx/data/Observable.h> + +namespace odemx { + namespace base { + namespace continuous { + + /** Choice which error is checked while integration + */ + enum ErrorType { + absolute, relative + }; + + class Monitor; + + class VariableContainer; + + class ODESolverObserver; + + /** \class ODESolver + + \ingroup base + + \brief Abstract class for implementing a solver + + This class specifies the interface of a solver as seen by the monitor. + + \note ODESolver supports Observation + + \note ODESolver supports Trace + + \note ODESolver supports Logging + + \sa Monitor, GSLSolver + + \since 3.0 + */ + class ODESolver : public data::Producer, public data::Observable<ODESolverObserver> { + public: + /** \brief Construction + \param sim + reference to one simulation-object + */ + ODESolver(Simulation& sim); + /// destruction + virtual ~ODESolver(); + + /** \brief Returns a variable container suitable for this Solver + \param size + initial size of arrays in the variable container + */ + virtual VariableContainer* getVariableContainer(int size) = 0; + + /** \brief Makes one integration step for monitor + \param time + internal time of assigned monitor. + + \note \p time is the time from which to do the step. + */ + virtual void makeStep(double time) = 0; + + /** \brief Initialize the solver + + \note This is also called if the monitor has changed. + */ + virtual void init() = 0; + + /** \name Monitor handling + + @{ + */ + /** \brief Sets the assigned Monitor + \param monitor + pointer to the monitor which manages this instance + */ + void setMonitor(Monitor* monitor); + + /** \brief Returns the assigned Monitor + */ + Monitor* getMonitor(); + //@} + + /** \name Solving parameters + + @{ + */ + /** \brief Sets the error limit for integration + */ + void setErrorLimit(double maxError); + + /** \brief Returns the error limit for integration + */ + double getErrorLimit(); + + /** \brief Sets the type of error which will be checked + \param type + is 'absolute' or 'relative' + */ + void setErrorType(ErrorType type); + + /** \brief Sets the interval for the step length of one integration step + \param min + lower bound of step length + \param max + upper bound of step length + */ + void setStepLength(double min, double max); + + /** \brief gives the size of the last step done + */ + double getStepLength(); + //@} + + protected: + // pointer to the Monitor which holds the Continuous objects which will be integrated + Monitor* monitor; + + /** \brief Calls all derivates functions of all ODEObject objects assigned to Continuous objects which are managed by the monitor + + \note This function evaluates all equations of all continuous processes as one function + as sum of partial functions at time internalTime + time. + \note This function is passed to the GSL Library for solving the ordinary differential equations. + */ + void evalF(double time); + + /** \brief Calls all jacbian functions of all ODEObject objects assigned to Continuous objects which are managed by the monitor + + \note This function evaluates all jacobian functions of all continuous processes as one matrix + as sum of partial matrices at time internalTime + time. Also it evaluates the function for differentiating + the i-th component of f by time + \note This function is passed to the GSL Library for solving the ordinary differential equations, if a solving algorithm for + stiff equations is used. + */ + void evalJacobian(double time); + + /** \brief Returns the variables container of the assigned Monitor + */ + VariableContainer* getVariableContainerOfMonitor(); + + // error type which will be checked after each step to optimize step length + ErrorType errorType; + + //error limit which will be checked after each step to optimize step length + double errorLimit; + + // minimum step length allowed by user + double minStep; + + // maximum step length allowed by user + double maxStep; + + // step length of the last step + double lastStep; + + friend class Monitor; + }; + + /** \interface ODESolverObserver + + \author Sascha Qualitz + + \brief Observer for ODESolver specific events + + \sa Continuous + + \since 3.0 + */ + class ODESolverObserver: + public ProcessObserver + { + public: + virtual void onCreate( ODESolver* sender ) {} ///< Construction + virtual void onDestroy( ODESolver* sender ) {} ///< Destruction + + virtual void onSetMonitor( ODESolver* sender, Monitor* monitor ) {} ///< new Monitor set + + virtual void onGetVariableContainer() {} ///< create new VariableContainer and return a pointer to monitor + }; + + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_ODESOLVER_INCLUDED */ + diff --git a/odemx-lite/include/odemx/base/continuous/Rate.h b/odemx-lite/include/odemx/base/continuous/Rate.h new file mode 100644 index 0000000000000000000000000000000000000000..49d252c0497c3945e55f836769449a8e6bae04d5 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/Rate.h @@ -0,0 +1,138 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Rate.h + + \author Sascha Qualitz + + \date created at 2010/2/26 + + \brief Declaration of class odemx::base::continuous::Rate + + \sa Rate.cpp + + \since 3.0 + */ +#ifndef ODEMX_RATE_INCLUDED +#define ODEMX_RATE_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +namespace odemx { + namespace base { + namespace continuous { + + //Forward declaration + class Continuous; + + class ODEObject; + + class State; + + /** \class Rate + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling an equation-element of the left hand side of an equation. + Used in the derivates function in a derived class of ODEObject. + + To describe ordinary differential equations the user has to use this class. + + \sa State + \sa JacobiMatrix + \sa DfDt + */ + class Rate { + public: + /** + \brief Construction + + \note The variables continuous and index_ will be set to 0 + */ + Rate(); + /** + \brief Construction + \param continuous + pointer to the continuous object where the equation-element belongs to + + \note The variable index_ will be set to 0 + */ + Rate(Continuous* continuous); + + /// destruction + virtual ~Rate(); + + /** + \brief Overrides the assignment operator to store the value of type double in the variable container. + \param value + value to be set + */ + Rate& operator =(const double value); + + /** + \brief Overrides the index operator to set the internal variable index_ + \param index + index of the variable to get/set (range 0..(Dimension-1)) + */ + Rate& operator [](const unsigned i); + + /** + \brief Sets the continuous variable + \param continuous + pointer to the continuous object where this equation-element belongs to + */ + void setContinuous(Continuous* continuous); + + private: + + /** + \brief Sets the value of type double at index_ + \param value + value to be set + + \note setValue stores the value at the correct index, because index_ was set by the overwritten operator[] before. + */ + void setValue(double value); + + /** + \brief Returns the value of type double with given index index_ + + getValue returns the value from the correct index position, because index_ was set by the overwritten operator[] before. + */ + double getValue(); + + // pointer to the continuous object where the equation-element belongs to + Continuous* continuous; + + // index of the variable to get/set (range 0..(Dimension-1)) + unsigned index_; + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_RATE_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/State.h b/odemx-lite/include/odemx/base/continuous/State.h new file mode 100644 index 0000000000000000000000000000000000000000..904205a724f2ace64b129e4082c579c172c3275e --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/State.h @@ -0,0 +1,154 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file State.h + + \author Sascha Qualitz + + \date created at 2010/2/26 + + \brief Declaration of class odemx::base::continuous::State + + \sa State.cpp + + \since 3.0 + */ + +#ifndef ODEMX_STATE_INCLUDED +#define ODEMX_STATE_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +namespace odemx { + namespace base { + namespace continuous { + + //Forward declaration + class Continuous; + + class ODEObject; + + /** \class State + + \ingroup base + + \author Sascha Qualitz + + \brief Object for handling an equation-element of the right hand side of an equation. + Used in the derivates function in a derived class of ODEObject. + + To describe ordinary differential equations the user has to use this class. + + \sa Rate + \sa JacobiMatrix + \sa DfDt + */ + class State { + public: + /** + \brief Construction + + \note The variables continuous and index_ will be set to 0. + */ + State(); + /** + \brief Construction + \param continuous + pointer to the continuous object where the equation-element belongs to + + \note The variable index_ will be set to 0. + */ + State(Continuous* continuous); + + /// destruction + virtual ~State(); + + /** + \brief Overrides the double converting-operator, to convert implicit an object of type state to type double. + + \note If this operator is called, the double value is the value that is returned by the method + getValueForDerivative(index_) of the corresponding continuous-object. The variable index_ was + set to an index between 0 and continuous->getDimension-1 before. To set the variables index_ + see also the method operator []. + */ + operator double() { + return this->getValue(); + } + + /** + \brief Overrides the index operator to set the internal variable index_ + \param index + index of the variable to get/set (range 0..(Dimension-1)) + */ + State& operator [](const unsigned i); + + /** + \brief Sets the continuous variable + \param continuous + pointer to the continuous object where the equation-element belongs to + */ + void setContinuous(Continuous* continuous); + + /** + \brief Overrides the assignment operator to store the value of type double in the variable container + \param value + value to be set + + \note Values must not be changed while the responsible monitor is integrating. + */ + State& operator =(const double value); + + private: + /** + \brief Returns the value of type double with given index index_ + + getValue returns the value from the correct index, because index_ was set by the overwritten operator[] before. + */ + double getValue() const; + + /** + \brief Sets the value of type double at index_ + \param value + value to be set + + \note setValue stores the value at the correct index, because index_ was set by the overwritten operator[] before. + \note Values must not be changed while the responsible monitor is integrating. + */ + void setValue(double value); + + + // pointer to the continuous object where the equation-element belongs to + Continuous* continuous; + + // index of the variable to get/set (range 0..(Dimension-1)) + unsigned index_; + + friend class Rate; + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_STATE_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/StateEvent.h b/odemx-lite/include/odemx/base/continuous/StateEvent.h new file mode 100644 index 0000000000000000000000000000000000000000..f8f5d7d651a42f2c7f4c5b4e94dca9ee52e46081 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/StateEvent.h @@ -0,0 +1,117 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file StateEvent.h + + \author Michael Fiedler + + \date created at 2008/11/21 + + \brief Declaration of StateEvent + + \sa Monitor + + \since 3.0 + */ + +#ifndef ODEMX_STATEEVENT_INCLUDED +#define ODEMX_STATEEVENT_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/ODESolver.h> +#include <odemx/data/Producer.h> +#include <odemx/data/Observable.h> + +namespace odemx { + namespace base { + namespace continuous { + + //forward declaration + class StateEventObserver; + + /** \class StateEvent + + \ingroup base + + \author Michael Fiedler + + \brief Check for conditions while integration and specify action + + The class StateEvent is for checking if continuous processes arrives a special state + specified by condition and than triggers an event specified by action + + \since 3.0 + */ + class StateEvent { + public: + /// destruction + virtual ~StateEvent(); + + /** \name Handle assigned Monitor + + @{ + */ + /** \brief Sets the Monitor where the StateEvent will be checked + \param monitor + pointer to the Monitor where it will be checked + + \note If this instance is already assigned to a Monitor it will automatically be transferred. + \note If \p monitor is NULL the StateEvent will be removed from an assigned Monitor. + */ + void setMonitor(Monitor *monitor); + + /** \brief Returns the Monitor where this StateEvent belongs to + */ + Monitor* getMonitor(); + //@} + + /** \brief Condition which will be checked + + This is to be implemented by the user. When condition returns true the action will be triggered by the monitor. + + \note If condition is true when added to the Monitor, then the action will be triggered immediately. + */ + virtual bool condition(SimTime time) = 0; + + /** \brief Action which will be executed when condition occurs + + This is to be implemented by the user. When condition returns true this action will be triggered by the monitor. + + \note If condition is true when added to the Monitor, then action will be triggered immediately. + */ + virtual void action() = 0; + + private: + // Monitor where the StateEvent will be checked + Monitor *monitor; + + friend class Monitor; + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_STATEEVENT_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/continuous/VariableContainer.h b/odemx-lite/include/odemx/base/continuous/VariableContainer.h new file mode 100644 index 0000000000000000000000000000000000000000..9f8a65ae935d47325882d99d1ad46cc23b4333b6 --- /dev/null +++ b/odemx-lite/include/odemx/base/continuous/VariableContainer.h @@ -0,0 +1,208 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file VariableContainer.h + + \author Michael Fiedler + + \date created at 2008/11/21 + + \brief Declaration of VariableContainer + + \since 3.0 + */ + +#ifndef ODEMX_VARIABLECONTAINER_INCLUDED +#define ODEMX_VARIABLECONTAINER_INCLUDED + +#include <odemx/setup.h> + +// usage of this class requires SimTime type double, +// which can be switched at compile time by defining +// ODEMX_USE_CONTINUOUS in file odemx/setup.h +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Monitor.h> + +namespace odemx { + namespace base { + namespace continuous { + + /** \class VariableContainer + + \ingroup base + + \brief Abstract class for implementing memory handling of a solver. + + \sa ODESolver, Monitor + + \since 3.0 + */ + class VariableContainer { + public: + /// destruction + virtual ~VariableContainer(); + + /** \brief Adapts the numbers of variables which can be stored in the container + \param newSize + new size of container + + \note Old content is preserved as long as it fits in \p newSize, everything over will be truncated. + */ + virtual void adaptSizeTo(int newSize) = 0; + + /** \name Variables + + Variables are for holding values, while derivatives, jacobi and DfDt are for calculating. + + @{ + */ + /** \brief Sets all variables to 0.0 + */ + virtual void nullVariables() = 0; + + /** \brief Sets value of one variable + \param num + index of variable on which \p value is set + */ + virtual void setVariable(int num, double value) = 0; + + /** \brief Returns the value of one variable + \param num + index of returned variable + */ + virtual double getVariable(int num) = 0; + //@} + + /** \name temporary values + + These values are used during the calculation of the intermediate steps. + + @{ + */ + /** \brief Sets all temporary variables to 0.0 + */ + virtual void nullValues() = 0; + + /** \brief Copies values of temporary variables to the corresponding variables + */ + virtual void copyVariablesToValues() = 0; + + /** \brief Sets value of one temporary variable + \param num + index of variable on which \p value is set + */ + virtual void setValue(int num, double value) = 0; + + /** \brief Returns value of one temporary variable + \param num + index of returned variable + */ + virtual double getValue(int num) = 0; + //@} + + /** \name derivatives + + @{ + */ + /** \brief Sets all derivative values to 0.0 + */ + virtual void nullDerivatives() = 0; + + /** \brief Sets value of one derivative variable + \param num + index of variable on which \p value is set + */ + virtual void setDerivative(int num, double value) = 0; + + /** \brief Adds value to one derivative variable + \param num + index of variable to which \p value will be added + */ + virtual void addToDerivative(int num, double value) = 0; + + /** \brief Returns value of one derivative variable + \param num + index of returned variable + */ + virtual double getDerivative(int num) = 0; + //@} + + /** \name jacobi + + @{ + */ + /** \brief Sets all jacobian values to 0.0 + */ + virtual void nullJacobi() = 0; + + /** \brief Sets value of one jacobian variable + + Sets variable(\p i ,\p j ) to \p value. + */ + virtual void setJacobi(int i, int j, double value) = 0; + + /** \brief Sets value of one jacobian variable + + Adds \p value to variable(\p i ,\p j ). + */ + virtual void addToJacobi(int i, int j, double value) = 0; + + /** \brief Returns value of one jacobian variable + + \return variable of index (\p i ,\p j ) + */ + virtual double getJacobi(int i, int j) = 0; + //@} + + /** \name DfDt + + right hand side derived by time + + @{ + */ + /** \brief Sets all derived components to 0.0 + */ + virtual void nullDfDt() = 0; + + /** \brief Sets value of one derived component + \param num + index of derived component on which \p value is set + */ + virtual void setDfDt(int num, double value) = 0; + + /** \brief Adds value to one derived component + \param num + index of derived component to which \p value will be added + */ + virtual void addToDfDt(int num, double value) = 0; + + /** \brief Returns value of one derived component + \param num + index of returned derived component + */ + virtual double getDfDt(int num) = 0; + //@} + }; + } + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + +#endif /* ODEMX_VARIABLECONTAINER_INCLUDED */ diff --git a/odemx-lite/include/odemx/base/control/Control.h b/odemx-lite/include/odemx/base/control/Control.h new file mode 100644 index 0000000000000000000000000000000000000000..78fd5236d844b40808a23cd6eb254373d93c50cd --- /dev/null +++ b/odemx-lite/include/odemx/base/control/Control.h @@ -0,0 +1,239 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Control.h + * @author Jonathan Schlue + * @date created at 2016/10/06 + * @brief Header declaration and header-only definitions of all class templates for Control Variables for built-in types. + * @sa ControlBase.h + * @sa ControlBase.cpp + * @since 3.1 + */ + +#ifndef ODEMX_BASE_CONTROL_INCLUDED +#define ODEMX_BASE_CONTROL_INCLUDED + +#include <type_traits> + +#include <odemx/base/control/ControlBase.h> + + +namespace odemx { +namespace base { + +/** \class Control + + \ingroup base + + \author Jonathan Schlue + + \brief %Control represents and acts as a general interface for control variables of built-in types. + + %Control variables wrap variables of built-in types. All increment, decrement and binary assignment operators are overloaded, so that + changes to the variable are recognized and registered processes are alerted using ControlBase's signal() method. Apart from that, + control variables act exactly as their wrapped built-in type. Use "Control<T>" as a type for variable declarations, where T may be any build-in type. + + \note Waiting processes are alerted only if the variable value changes. + + \note All operators are overloaded in a canonical manner. For implementation details please refer to the source code directly. + + \since 3.1 +*/ +template <typename T> +class Control: public ControlBase +{ + static_assert( + std::is_integral<T>::value, + "Only integral build-in types may be used as control variables." + ); + +public: + Control() = default; + + Control(const T& val) + : val_(val) + {} + + operator T() const + { + return val_; + } + + // ASSIGNMENT + + Control<T>& operator=(const T& other) + { + if (val_ != other) + { + val_ = other; + signal(); + } + return *this; + } + + // BINARY ASSIGNMENT ARITHMETICS + + Control<T>& operator+=(const T& other) + { + if (other != 0) + { + val_ += other; + signal(); + } + return *this; + } + + Control<T>& operator-=(const T& other) + { + if (other != 0) + { + val_ -= other; + signal(); + } + return *this; + } + + Control<T>& operator*=(const T& other) + { + if (val_ != 0 && other != 1) + { + val_ *= other; + signal(); + } + return *this; + } + + Control<T>& operator/=(const T& other) + { + if (val_ != 0 && other != 1) + { + val_ /= other; + signal(); + } + return *this; + } + + // BINARY ASSIGNMENT MODULO + + std::enable_if<std::is_integral<T>::value, Control<T>&> operator%=(const T& other) + { + T res = val_ % other; + if (res != val_) + { + val_ = res; + signal(); + } + return *this; + } + + // BINARY ASSIGNMENT BITWISE + + std::enable_if<std::is_integral<T>::value, Control<T>&> operator^=(const T& other) + { + T res = val_ ^ other; + if (val_ != res) + { + val_ = res; + signal(); + } + return *this; + } + + std::enable_if<std::is_integral<T>::value, Control<T>&> operator&=(const T& other) + { + T res = val_ & other; + if (val_ != res) + { + val_ = res; + signal(); + } + return *this; + } + + std::enable_if<std::is_integral<T>::value, Control<T>&> operator|=(const T& other) + { + T res = val_ | other; + if (val_ != res) + { + val_ = res; + signal(); + } + return *this; + } + + std::enable_if<std::is_integral<T>::value, Control<T>&> operator<<=(unsigned shift) + { + if (shift != 0) + { + val_ <<= shift; + signal(); + } + return *this; + } + + std::enable_if<std::is_integral<T>::value, Control<T>&> operator>>=(unsigned shift) + { + if (shift != 0) + { + val_ >>= shift; + signal(); + } + return *this; + } + + // INCREMENT + + std::enable_if<!std::is_same<T,bool>::value, Control<T> > operator++(int) + { + Control<T> temp = *this; + ++*this; + return temp; + } + + std::enable_if<!std::is_same<T,bool>::value, Control<T>&> operator++() + { + ++val_; + signal(); + return *this; + } + + // DECREMENT + + std::enable_if<!std::is_same<T,bool>::value, Control<T> > operator--(int) + { + Control<T> temp = *this; + --*this; + return temp; + } + + std::enable_if<!std::is_same<T,bool>::value, Control<T>&> operator--() + { + --val_; + signal(); + return *this; + } + +private: + T val_; +}; + +} // END namespace base +} // END namespace odemx + +#endif //ODEMX_BASE_CONTROL_INCLUDED diff --git a/odemx-lite/include/odemx/base/control/ControlBase.h b/odemx-lite/include/odemx/base/control/ControlBase.h new file mode 100644 index 0000000000000000000000000000000000000000..ad97ff506a5e096d81f0e6ccbb996efd9742980d --- /dev/null +++ b/odemx-lite/include/odemx/base/control/ControlBase.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ControlBase.h + * @author Jonathan Schlue + * @date created at 2016/10/06 + * @brief Header declaration of a base a class for all Control variables, signaling informed lambda expressions on change. + * @sa Control.h + * @sa IMemory.h + * @since 3.1 + */ + +#ifndef ODEMX_BASE_CONTROLBASE_INCLUDED +#define ODEMX_BASE_CONTROLBASE_INCLUDED + +#include <map> + +#include <odemx/base/TypeDefs.h> +#include <odemx/synchronization/IMemory.h> + + +namespace odemx { +namespace base { + + +/** \class ControlBase + + \ingroup base + + \author Jonathan Schlue + + \brief ControlBase acts as base class for all control variable types. + + \note ControlBase supports Process alertion. + + ControlBase implements the IMemory interface to act as an alerter for remembered, waiting processes. + Control variables are subclass of ControlBase and alert waiting processes on change. + ControlBases are not instantiable, only Control variables are. + + \since 3.1 +*/ +class ControlBase : public odemx::synchronization::IMemory +{ +public: + + /// Destruction + virtual ~ControlBase() + {} + + /// Get the Control variable memory type: "CONTROL" + virtual Type getMemoryType() const override; + friend class Process; + +protected: + + /// Protected copy constructor to forbid user instantiation + ControlBase(const ControlBase&) = default; + + /// Protected move constructor to forbid user movement + ControlBase(ControlBase&&) = default; + + /// Protected compiler generated default constructor + ControlBase() = default; + + /// Wake up all waiting processes using FIFO strategy by calling their hold() method + void signal(); + +private: + virtual bool isAvailable() override; + virtual void alert() override; + virtual bool remember(base::Sched* newObject) override; + virtual bool forget(base::Sched* rememberedObject) override; + virtual void eraseMemory() override; + + /// Private copy assignment to forbid usage + ControlBase& operator =(const ControlBase&) = default; + + /// Private move assignment to forbid usage + ControlBase& operator =(ControlBase&&) = default; + + /** + * \brief List of all registered, waiting processes + * + * Processe are registed, whenever they wait until an arbitrary condition comes true using their waitUntil() method. + * All involved and explicitely listed control variables then register these processes and alert them on change to eventually + * check their condition again. + */ + ProcessList waitingProcesses_; +}; + +} +} + +#endif //ODEMX_BASE_CONTROLBASE_INCLUDED diff --git a/odemx-lite/include/odemx/coroutine/Coroutine.h b/odemx-lite/include/odemx/coroutine/Coroutine.h new file mode 100644 index 0000000000000000000000000000000000000000..7dddc217659fd1bced9d23f71e41a395506bccd2 --- /dev/null +++ b/odemx-lite/include/odemx/coroutine/Coroutine.h @@ -0,0 +1,235 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Coroutine.h + * @author Ralf Gerstenberger + * @date created at 2002/01/22 + * @brief Declaration of odemx::coroutine::Coroutine and observer + * @sa Coroutine.cpp + * @since 1.0 + */ + +#ifndef ODEMX_CORO_COROUTINE_INCLUDED +#define ODEMX_CORO_COROUTINE_INCLUDED + +#include <odemx/coroutine/System.h> +#include <odemx/coroutine/CoroutineContext.h> +#include <odemx/data/Observable.h> + +namespace odemx { +namespace coroutine { + +// forward declaration +class CoroutineObserver; + +/** \class Coroutine + + \ingroup coroutine + + \author Ralf Gerstenberger + + \brief Coroutine implements a function capable of switching execution to and back from another Coroutine inside function body. + + \note Coroutine supports Observation. + + Coroutine is a system dependable but portable coroutine implementation. A coroutine is + a function capable of switching execution to a point inside another coroutine and back to + a point inside its own function body. + The implementation is stack-based for Linux (based on concepts from Stroustrup "Task-Library", + AT&T 1991 and Hansen "The C++ -Answer Book", Addison Wesley 1990) and Fiber-based for + Microsoft Windows 98 and later (based on process implementation in ODEM by Martin von Löwis). + + The stack-based implementation should be portable to any platform using linear, continuous stacks + (growing bottom up or top down) with a C++ (and exception handling) compatible setjmp()/longjmp() + implementation. + + \warning Sun (Ultra)Sparc platform has a circular stack and is not supported at the moment. + \warning IA-64 platform stores the return address of a function in a special branch register; not supported. + + \since 1.0 +*/ +class Coroutine +: public data::Observable< CoroutineObserver > +{ +public: + /** + \brief Coroutine states + + A Coroutine transits through 3 states during its lifetime. + After creation it is in state CREATED. First time the Coroutine + is activated it transits to RUNNABLE. When Coroutine returns + it becomes TERMINATED. + */ + enum State + { + CREATED, ///< initial state + RUNNABLE, ///< working state + TERMINATED ///< final state + }; + + /** + \brief start/continue execution of this Coroutine. + \note The Coroutine will become the active Coroutine in its CoroutineContext. + \note There is no more than one Coroutine active in its context at any time. + */ + void switchTo(); + + /** + \copydoc Coroutine::switchTo + */ + void operator()(); + + /// Returns control to the parent coroutine, or - if none exists - to the context + void yield(); + +public: + /** + \brief Construction + \param c + pointer to CoroutineContext of this Coroutine + (if c==0 a default CoroutineContext is used) + \param o + pointer to a CoroutineObserver + + \sa DefaultContext + */ + Coroutine( CoroutineContext* c = 0, CoroutineObserver* o = 0 ); + + virtual ~Coroutine(); ///< Destruction + + /** + \brief coroutine state + \return current state of Coroutine + \sa Coroutine::State + */ + State getState() const; + + /** + \brief get CoroutineContext of Coroutine + \return CoroutineContext of this Coroutine + */ + CoroutineContext* getContext(); + + /** + \brief parent of coroutine + \return parent (first caller) of coroutine + \retval 0 + parent is CoroutineContext + \retval !=0 + pointer to parent coroutine + */ + Coroutine* getParent(); + + /** + \brief last caller + \return last caller of coroutine + \retval 0 + last caller is CoroutineContext + \retval !=0 + pointer to coroutine + */ + Coroutine* getCaller(); + + /// @todo private & Scheduler as friend? -- only Scheduler will call this method! + void freeStack (); + +protected: + // Coroutine entry point + virtual void run() = 0; ///< define this method to implement Coroutine behaviour + void clear(); ///< called after execution finished in switchTo(), or in destructor + + // Implementation +private: + CoroutineContext* context; ///< CoroutineContext of this Coroutine + Coroutine* parent; ///< return point after start() finished + Coroutine* caller; ///< last caller of coroutine + + State state; ///< Coroutine state + + void initialize(); ///< called before first execution + + State setState( State newState ); ///< state transitions + + // System dependent + /// \name Fiber based implementation + //@{ + LPVOID myFiber; + LPVOID fiber; + //@} + + /// \name Fiber based implementation + //@{ + /// prepare execution switch (save active fiber). + void saveFiber(); + //@} + + friend VOID CALLBACK ExecFiber( PVOID ); + friend void FiberSwitch( LPVOID fiber ); + +}; + +/** \interface CoroutineObserver + + \author RalfGerstenberger + + \brief Observer for Coroutine specific events. + + \sa Coroutine + + \since 1.0 +*/ +class CoroutineObserver { +public: + virtual ~CoroutineObserver() {} + + virtual void onCreate( Coroutine* sender ) {} ///< creation + virtual void onDestroy( Coroutine* sender ) {} ///< destruction + + virtual void onInitialize( Coroutine* sender ) {} ///< initialisation + virtual void onClear( Coroutine* sender ) {} ///< Coroutine is cleared + + /// execution switches between Coroutines + virtual void onSwitchTo( Coroutine* sender, Coroutine* previousActive ) {} + /// execution switches from Context to Coroutine + virtual void onSwitchTo( Coroutine* sender, CoroutineContext* previousActive ) {} + + /// state transition + virtual void onChangeState( Coroutine* sender, Coroutine::State oldState, + Coroutine::State newState ) {} +}; + +/** + \internal + \brief Fiber start function + \param p + pointer to a Coroutine +*/ +VOID CALLBACK ExecFiber( PVOID p ); + +/** + \internal + \brief encapsulates SwitchToFiber() call + \param fiber + pointer to fiber +*/ +void FiberSwitch( LPVOID fiber ); + +} } // namespace odemx::coroutine + +#endif /* ODEMX_CORO_COROUTINE_INCLUDED */ diff --git a/odemx-lite/include/odemx/coroutine/CoroutineContext.h b/odemx-lite/include/odemx/coroutine/CoroutineContext.h new file mode 100644 index 0000000000000000000000000000000000000000..8c08e63b4784a51e5a48651171165d8a6a85b223 --- /dev/null +++ b/odemx-lite/include/odemx/coroutine/CoroutineContext.h @@ -0,0 +1,187 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file CoroutineContext.h + * @author Ralf Gerstenberger + * @date created at 2002/02/04 + * @brief Declaration of odemx::coroutine::CoroutineContext, observer, and DefaultContext + * @sa CoroutineContext.cpp + * @since 1.0 + */ + +#ifndef ODEMX_CORO_COROUTINECONTEXT_INCLUDED +#define ODEMX_CORO_COROUTINECONTEXT_INCLUDED + +#include <odemx/coroutine/System.h> +#include <odemx/data/Observable.h> + +#include <cassert> +#include <typeinfo> +#include <exception> + +namespace odemx { +namespace coroutine { + +// forward declaration +class Coroutine; +class CoroutineContextObserver; + +/** \class CoroutineContext + + \ingroup coroutine + + \author Ralf Gerstenberger + + \brief Context for executing Coroutines. + + \note CoroutineContext supports Observation. + + \sa CoroutineContextObserver. + + A CoroutineContext encapsulates the main program. It is required for the use of Coroutine. + Execution can be switched between Coroutine and CoroutineContext. + The implementation is stack-based for Linux (based on concepts from Stroustrup "Task-Library", + AT&T 1991 and Hansen "The C++ -Answer Book", Addison Wesley 1990) or Fiber-based + for Microsoft Windows 98 and later (based on process implementation in ODEM by Martin von L�wis). + + The stack-based implementation should be portable to any platform using linear, continuous stacks + (growing bottom up or top down) with a C++ (and exception handling) compatible setjmp()/longjmp() + implementation. + + \since 1.0 +*/ +class CoroutineContext +: public data::Observable< CoroutineContextObserver > +{ +public: + /// Construction + CoroutineContext( CoroutineContextObserver* o = 0 ); + /// Destruction + virtual ~CoroutineContext(); + + /// Call this method to continue execution in the coroutine context + void switchTo(); + + friend class Coroutine; + +protected: + /// Get a pointer to the currently running coroutine + Coroutine* getActiveCoroutine(); + /// Get the number of registered coroutines of this context + unsigned int getNumberOfCoroutines(); + +private: + Coroutine* activeCoroutine; ///< active Coroutine + unsigned int numberOfCoroutines; ///< counter of Coroutines in this context + + /** \brief set active Coroutine + \param c + pointer to next active Coroutine + + \return previous active Coroutine + \note There is no more than one Coroutine active in a context at any time. + */ + Coroutine* setActiveCoroutine( Coroutine* c ); + + /** + \brief register new Coroutine in this context + \param cr + pointer to new Coroutine + */ + void beginCoroutine( Coroutine* cr ); + + /** + \brief Coroutine in this context has finished + \param cr + pointer to finished Coroutine + */ + void endCoroutine( Coroutine* cr ); + + /// \name Fiber based implementation + //@{ + LPVOID fiber; ///< pointer to context Fiber + static bool initFibers; ///< ConvertThreadToFiber called + //@} + + /// \name Fiber based implementation + //@{ + void saveFiber(); ///< save current execution point + //@} + + friend VOID CALLBACK ExecFiber( PVOID ); + friend void FiberSwitch( LPVOID fiber ); +}; + +/** \class CoroutineContextObserver + + \author RalfGerstenberger + + \brief Observer for CoroutineContext specific events. + + \sa CoroutineContext + + \since 1.0 +*/ +class CoroutineContextObserver { +public: + virtual ~CoroutineContextObserver() {} + + virtual void onCreate( CoroutineContext* sender ) {} ///< creation + virtual void onDestroy( CoroutineContext* sender ) {} ///< destruction + + /// execution switches from Coroutine to CoroutineContext + virtual void onSwitchTo( CoroutineContext* sender, Coroutine* previousActive ) {} + + /// active Coroutine changed (oldActive and newActive might be 0) + virtual void onChangeActiveCoroutine( CoroutineContext* sender, + Coroutine* oldActive, Coroutine* newActive ) {} +}; + +/** + * @brief Get a default coroutine context + * @return pointer to the DefaultContext + * @relates DefaultContext + */ +extern CoroutineContext* getDefaultContext(); + +/** \class DefaultContext + + \author Ralf Gerstenberger + + \brief Default CoroutineContext for convenience. + + The DefaultContext is provided for convenience. You can + use this context if you don't want to define your own. + + The DefaultContext is returned by getDefaultContext(). + + \since 1.0 +*/ +class DefaultContext +: public CoroutineContext +{ +private: + /// Construction only via getDefaultContext + DefaultContext(); + friend CoroutineContext* getDefaultContext(); +}; + +} } // namespace odemx::coroutine + +#endif /* ODEMX_CORO_COROUTINECONTEXT_INCLUDED */ diff --git a/odemx-lite/include/odemx/coroutine/System.h b/odemx-lite/include/odemx/coroutine/System.h new file mode 100644 index 0000000000000000000000000000000000000000..7d86e5989ce219b8ba588f297dc09e19573e5413 --- /dev/null +++ b/odemx-lite/include/odemx/coroutine/System.h @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file System.h + * @author Ralf Gerstenberger + * @date created at 2002/02/04 + * @brief OS- and platform-specific includes, defines and types + * @since 1.0 + */ + +#ifndef ODEMX_CORO_SYSTEM_INCLUDED +#define ODEMX_CORO_SYSTEM_INCLUDED + +#include <odemx/setup.h> + +#ifdef _WIN32 + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 + #endif + #ifndef WINVER + #define WINVER 0x0400 + #endif + #define WIN32_LEAN_AND_MEAN + #include <windows.h> +#else + #include <odemx/coroutine/ucFiber.h> +#endif + +#endif /* ODEMX_CORO_SYSTEM_INCLUDED */ diff --git a/odemx-lite/include/odemx/coroutine/ucFiber.h b/odemx-lite/include/odemx/coroutine/ucFiber.h new file mode 100644 index 0000000000000000000000000000000000000000..50f8dec213717b83341c112cb75f300e5d52cf21 --- /dev/null +++ b/odemx-lite/include/odemx/coroutine/ucFiber.h @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ucFiber.h + * @author Klaus Ahrens + * @date created at 2009/03/16 + * @brief Declaration of class ucFiber + * @sa ucFiber.cpp + * @since 3.0 + */ + +#ifndef ODEMX_UCFIBER_INCLUDED +#define ODEMX_UCFIBER_INCLUDED + +#ifndef _WIN32 + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 520 +#endif + +// The value SIGSTKSZ is a system default specifying the number of bytes that +// would be used to cover the usual case when manually allocating an alternate +// stack area +// defined in signal.h +#include <signal.h> + +// this is too small an area on a 64 bit system (using 32k fixed size) +//#ifdef SIGSTKSZ +// #define ODEMX_DEFAULT_STACK_SIZE SIGSTKSZ +//#else + #define ODEMX_DEFAULT_STACK_SIZE (32*1024) +//#endif + +// make ucFiber compatible with the Windows API +#define CALLBACK +typedef void VOID; +typedef void* LPVOID; +typedef int PVOID; // looks strange but is OK, because all coroutines + // pointers are tunneled as indices into a map ! + +#include <ucontext.h> +#include <cstdlib> +#include <map> + + +namespace odemx { +namespace coroutine { + +/** + * @brief Fiber implementation wrapping the POSIX user context in a fiber API + * @ingroup coroutine + * @author Klaus Ahrens + * @since 3.0 + */ +class ucFiber { +public: + + ucFiber(void* param); + ucFiber(std::size_t stacksize, void (*start)(void*), void* param); + ~ucFiber(); + + static ucFiber* current; + + static void* ConvertThreadToFiber(void* param); + static void* GetCurrentFiber(); + static void* CreateFiber(std::size_t stacksize, void (*start)(void*), void* param); + static void DeleteFiber(void* fiber); + static void SwitchToFiber(void* fiber); + + static void stackcheck(); + static void* getCoroutine(int nr); + +private: + ucontext_t* uc_; + void* callStack_; + enum StackState {mainStack, okStack, noStack} stackState_; + void* tos; + static std::map<int, void*> allFibers; + static int nFibers; +}; + +#define GLOBAL_WRAPPERS +#ifdef GLOBAL_WRAPPERS + +inline void* ConvertThreadToFiber(void* param) +{ return ucFiber::ConvertThreadToFiber(param); } + +inline void* GetCurrentFiber() +{ return ucFiber::GetCurrentFiber(); } + +inline void* CreateFiber(std::size_t stacksize, void (*start)(void*), void* param) +{ return ucFiber::CreateFiber(stacksize, start, param); } + +inline void DeleteFiber(void* fiber) +{ return ucFiber::DeleteFiber(fiber); } + +inline void SwitchToFiber(void* fiber) +{ return ucFiber::SwitchToFiber(fiber); } + +inline void stackcheck() +{ return ucFiber::stackcheck(); } + +#endif /* GLOBAL_WRAPPERS */ + +#endif /* _WIN32 */ + +} } // namespace odemx::coroutine + +#endif /* ODEMX_UCFIBER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/Label.h b/odemx-lite/include/odemx/data/Label.h new file mode 100644 index 0000000000000000000000000000000000000000..34bc1905fb207add062ff89c0ff1bb841de392ab --- /dev/null +++ b/odemx-lite/include/odemx/data/Label.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Label.h + * @author Ronald Kluth + * @date created at 2009/09/19 + * @brief Declaration of type odemx::data::Label + * @since 3.0 + */ + +#ifndef ODEMX_DATA_LABEL_INCLUDED +#define ODEMX_DATA_LABEL_INCLUDED + +#include <string> + +namespace odemx { +namespace data { + +/** + * @brief String type used for object labels in ODEMx + * + * Every model element class that is derived from class @c odemx::data::Producer + * provides unique names for its objects. This is ensured by the simulation context, + * which must always be provided. Access to the unique name is given with the method + * getLabel(). + * + * @see odemx::data::Producer + */ +typedef std::string Label; + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_LABEL_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/LoggingManager.h b/odemx-lite/include/odemx/data/LoggingManager.h new file mode 100644 index 0000000000000000000000000000000000000000..2081582503e528636204eb3e75697770fee06945 --- /dev/null +++ b/odemx-lite/include/odemx/data/LoggingManager.h @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file LoggingManager.h + * @author Ronald Kluth + * @date created at 2009/03/18 + * @brief Declaration of odemx::data::LoggingManager + * @sa LoggingManager.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_LOGGINGMANAGER_INCLUDED +#define ODEMX_DATA_LOGGINGMANAGER_INCLUDED + +#include <odemx/setup.h> +#include <odemx/base/SimTime.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/SimRecord.h> +#include <odemx/data/output/DefaultLoggingType.h> +#include <CppLog/ChannelManager.h> + +#include <string> + +namespace odemx { +namespace data { + +//----------------------------------------------------------forward declarations + +class StatisticsReport; +struct DefaultLogConfig; + +//-----------------------------------------------------------header declarations + +/** + * @brief Facilitates log channel management, error logging, and default logging + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::Producer, ODEMX_DECLARE_DATA_CHANNEL + * + * The logging manager is a base class for the simulation context. It is + * primarily responsible for creating and providing access to the log + * channels that ODEMx provides by default: + * @li trace + * @li debug + * @li info + * @li warning + * @li error + * @li fatal + * @li statistics + * + * All of those channels use the record type @c odemx::data::SimRecord. + * Access to the channels is automatically provided within subclasses of + * @c odemx::data::Producer. + * + * Another function of this class is the provision of a name scope for + * uniquely labeled objects within one simulation context. All data producers + * must request a label from the logging manager, which will ensure its + * uniqueness by appending numbers if a particular label already exists. + * + * Finally, the class handles the initialization of error logging components. + * The channels warning, error and fatal can be used by data producers to + * notify the user of possible problems. Upon initialization of the manager, + * it creates an instance of odemx::data::output::ErrorWriter and registers + * it with these channels. + * + * @note Care must be taken if all consumers are removed from a log channel, + * as this will include the error writer as well. + */ +class LoggingManager +: public Log::ChannelManager< SimRecord > +{ +public: + /// Construction + LoggingManager(); + /// Construction with different default label and spacer for named elements + LoggingManager( const std::string& defLabel, const char defSpace ); + /// Destruction + virtual ~LoggingManager(); + + /** + * @brief Activates the default logging functionality + * @param type Determines the type of logging consumer used + * @param location Determines the location for XML and database output + * @retval @c true if the activation was successful + * @retval @c false if the the default logging was already enabled + * + * Default logging simply means initializing one log consumer and + * registering that with all provided channels. The type of the log + * consumer can be determined by the first parameter: + * @li STDOUT creates an odemx::data::output::OStreamWriter for the console + * @li XML creates an odemx::data::output::XmlWriter for XML file output. + * This requires the provision of a base name for the files as second argument. + * @li DATABASE creates an odemx::data::output::DatabaseWriter. This also + * requires a second argument, which must be a connection string for the + * target database. In the case of SQLite, this will be a file name. + * When using ODBC, it must specify driver and user settings. + * + * Additionally, an odemx::data::buffer::StatisticsBuffer object is + * registered with the statistics channel in order to automatically + * collect statistical data. + */ + bool enableDefaultLogging( output::Type type, const std::string& location = "" ); + + /** + * @brief Deactivates the default logging functionality + * @retval @c true if the deactivation was successful + * @retval @c false if the the default logging was not enabled + * + * Both, the default writer, and the statistics buffer objects will be + * removed from the channels and thereby be destroyed. + */ + bool disableDefaultLogging(); + + /** + * @brief Reset the data stored in the statistics buffer + * @param currentTime The current simulation time passed to the statistics buffer. + * @retval @c true if the reset was successful + * @retval @c false if the the default logging was disabled + * @note This requires the default logging to be active + */ + bool resetDefaultStatistics( base::SimTime currentTime ); + + /** + * @brief Create a report from the collected statistical data + * @param type SDTOUT or XML to choose where to create the report + * @param location Required when using XML, this will be used as file name. + * @retval @c true if the reset was successful + * @retval @c false if the the default logging was disabled + * @note This requires the default logging to be active + */ + bool reportDefaultStatistics( output::Type type, const std::string& location = "" ); + +private: + /// Manages the default logging configuration, if one is set + std::unique_ptr< DefaultLogConfig > defaultLogConfig_; + +private: + /** + * @brief Registers an ErrorWriter with channels warning, error and fatal. + * + * This helper method is called automatically during construction. + */ + void initErrorLogging(); +}; + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_LOGGINGMANAGER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/ManagedChannels.h b/odemx-lite/include/odemx/data/ManagedChannels.h new file mode 100644 index 0000000000000000000000000000000000000000..fa21767cb1d510d7856919806f45c5ab01fec5ff --- /dev/null +++ b/odemx-lite/include/odemx/data/ManagedChannels.h @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ManagedChannels.h + * @author Ronald Kluth + * @date created at 2009/09/05 + * @brief Declaration of ODEMx default log channels and various macros + * @sa ManagedChannels.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_MANAGEDCHANNELS_INCLUDED +#define ODEMX_DATA_MANAGEDCHANNELS_INCLUDED + +#include <CppLog/DeclareChannel.h> + +#ifdef ODEMX_USE_MACRO_COUNTER + +/** + * @def ODEMX_DECLARE_DATA_CHANNEL( PP_IdName ) + * @brief Declares a managed channel + * @see odemx::data::LoggingManager, odemx::data::Producer + * + * This macro is used internally to create the log channels provided by ODEMx. + * It ensures that each channel has a unique ID, and that subclasses of + * @c odemx::data::Producer automatically get access to these channels. This + * only works for the predefined channels, though. + * + * @note In case a compiler does not support the macro __COUNTER__ for ID + * generation, there is also a manual variant of the macro called + * ODEMX_DECLARE_DATA_CHANNEL_WITH_ID. + */ + +// macro for log channel declaration +#define ODEMX_DECLARE_DATA_CHANNEL( PP_IdName ) \ + CPPLOG_DECLARE_CHANNEL( odemx_detail, PP_IdName, odemx::data::SimRecord ); \ + namespace odemx { \ + namespace data { \ + namespace channel_id { \ + using odemx_detail::PP_IdName; \ + } } } // namespace odemx::data::channel_id + +#else + +#define ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( PP_IdName, PP_IdValue ) \ + CPPLOG_DECLARE_CHANNEL_WITH_ID( odemx_detail, PP_IdName, odemx::data::SimRecord, PP_IdValue ); \ + namespace odemx { \ + namespace data { \ + namespace channel_id { \ + using odemx_detail::PP_IdName; \ + } } } // namespace odemx::data::id + +#endif + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace data { +class SimRecord; +} } + +//-----------------------------------------------------------header declarations + +#ifdef ODEMX_USE_MACRO_COUNTER + +ODEMX_DECLARE_DATA_CHANNEL( trace ); +ODEMX_DECLARE_DATA_CHANNEL( debug ); +ODEMX_DECLARE_DATA_CHANNEL( info ); +ODEMX_DECLARE_DATA_CHANNEL( warning ); +ODEMX_DECLARE_DATA_CHANNEL( error ); +ODEMX_DECLARE_DATA_CHANNEL( fatal ); +ODEMX_DECLARE_DATA_CHANNEL( statistics ); + +#else + +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( trace, 1000 ); +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( debug, 1001 ); +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( info, 1002 ); +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( warning, 1003 ); +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( error, 1004 ); +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( fatal, 1005 ); +ODEMX_DECLARE_DATA_CHANNEL_WITH_ID( statistics, 1006 ); + +#endif + +/** + * @def ODEMX_TRACE + * @brief Macro to be used for trace logging in odemx classes + * + * This macro allows for ODEMx tracing to be turned on or off. It does so + * by wrapping the trace call in a condition that is either always true + * or always false. Modern compilers should completely optimize out + * code that contains <tt>if( false ) {...}</tt>. + */ +#define ODEMX_TRACE \ + if( ODEMX_TRACE_ENABLED ) this->trace + +namespace odemx { +namespace data { +namespace channel_id { + +/** + * @brief Get a string representation of a log channel name + * @param id The ID of the log channel + * @return The name of the log channel as string + * + * If other IDs than those know to ODEMx are given as argument, then + * the return value will simply state "user-defined". + */ +extern const std::string toString( const Log::ChannelId id ); + +} } } // namespace odemx::data::channel_id + +#endif /* ODEMX_DATA_MANAGEDCHANNELS_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/Observable.h b/odemx-lite/include/odemx/data/Observable.h new file mode 100644 index 0000000000000000000000000000000000000000..18c4979c8e406336b0b087793726420eea698200 --- /dev/null +++ b/odemx-lite/include/odemx/data/Observable.h @@ -0,0 +1,225 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Observable.h + * @author Ralf Gerstenberger + * @date created at 2002/02/11 + * @brief Declaration and implementation of odemx::data::Observable + * @since 1.0 + */ + +#if defined(_MSC_VER) +#pragma warning(disable : 4250 4786) +#endif + +#ifndef ODEMX_OBSERVABLE_INCLUDED +#define ODEMX_OBSERVABLE_INCLUDED + +#include <odemx/setup.h> + +#include <algorithm> +#include <list> + +namespace odemx { +namespace data { + +/** + * @brief Observable provides management of observers. + * @ingroup data + * @author Ralf Gerstenberger + * + * Observation is meant as an association scheme between two + * objects, one observed, one observing, that share an individual (observation) + * interface. The observed object reports events and attribute changes + * of some meaning through the interface to the observer, which implements this + * xxxObserver interface. The xxxObserver interface is defined along with the + * class of the observed object, where xxx is replaced with the class name. + * An Observer is a client to its observed object and managed by the class + * template Observable. A class that supports the observation scheme as a type + * for observed objects should use Observable as a base class. + * + * @note If ODEMX_USE_OBSERVATION is not defined in odemx/setup.h, + * this class is compiled as empty (base) class. + * + * @since 1.0 + */ +template< typename ObserverT > +class Observable +{ + +// this is essentially an empty base class if observation is disabled +#ifdef ODEMX_USE_OBSERVATION + +public: + /// Construction + Observable( ObserverT* obs = 0 ) + { + if( obs != 0 ) + { + observers.push_back( obs ); + } + } + + /// Get observer list + const std::list<ObserverT*>& getObservers() + { + return observers; + } + + /// Add an observer to the list + void addObserver( ObserverT* newObserver ) + { + typename std::list< ObserverT* >::iterator found + = std::find( observers.begin(), observers.end(), newObserver ); + + if( found == observers.end() ) + { + observers.push_back( newObserver ); + } + } + + /// Remove an observer from the list + void removeObserver( ObserverT* ob ) {observers.remove(ob);} + +private: + /// The list of registered observers + std::list< ObserverT* > observers; + +#else /* ODEMX_USE_OBSERVATION not defined */ + +public: + // for compatibility with derived classes, this empty constructor is needed + Observable( ObserverT* obs = 0 ) {} + +#endif /* ODEMX_USE_OBSERVATION */ + +}; + +#ifdef ODEMX_USE_OBSERVATION + +/** + \brief Broadcast event + + \ingroup data + + \param ObserverType + Type of observer (xxxObserver) + + \param Event + Event handler function without on ( Create(this)->onCreate(this) ) +*/ +#define ODEMX_OBS(ObserverType, Event) \ +{\ + for(std::list<ObserverType* >::const_iterator \ + i = data::Observable<ObserverType >::getObservers().begin(); \ + i != data::Observable<ObserverType >::getObservers().end(); ++i) \ + { \ + (*i)->on##Event;\ + } \ +} + +/** + \brief Broadcast attribute change + + \ingroup data + + \param ObserverType + Type of observer (xxxObserver) + + \param Attribute + Changed attribute name + + \param oldValue + Old value of attribute + + \param newValue + New value of attribute +*/ +#define ODEMX_OBS_ATTR(ObserverType, Attribute, oldValue, newValue) \ +{\ + for(std::list<ObserverType* >::const_iterator \ + i = data::Observable<ObserverType >::getObservers().begin(); \ + i != data::Observable<ObserverType >::getObservers().end(); ++i) \ + { \ + (*i)->onChange##Attribute(this, oldValue, newValue); \ + } \ +} + + +/** + \brief Broadcast event with observer interface template + + \ingroup data + + \param ObserverType + Type of observer (xxxObserver) + + \param Event + Event handler function without on ( Create(this)->onCreate(this) ) +*/ +#define ODEMX_OBS_T(ObserverType, Event) \ +{\ + for( typename std::list<ObserverType* >::const_iterator \ + i = data::Observable<ObserverType >::getObservers().begin(); \ + i != data::Observable<ObserverType >::getObservers().end(); ++i) \ + { \ + (*i)->on##Event;\ + } \ +} + +/** + \brief Broadcast attribute change with observer interface template + + \ingroup data + + \param ObserverType + Type of observer (xxxObserver) + + \param Attribute + Changed attribute name + + \param oldValue + Old value of attribute + + \param newValue + New value of attribute +*/ +#define ODEMX_OBS_ATTR_T(ObserverType, Attribute, oldValue, newValue) \ +{\ + for( typename std::list<ObserverType* >::const_iterator \ + i = data::Observable<ObserverType >::getObservers().begin(); \ + i != data::Observable<ObserverType >::getObservers().end(); ++i) \ + { \ + (*i)->onChange##Attribute(this, oldValue, newValue); \ + } \ +} + +#else /* ODEMX_USE_OBSERVATION not defined */ + +// disable all observation macros +#define ODEMX_OBS(ObserverType, Event) +#define ODEMX_OBS_ATTR(ObserverType, Attribute, oldValue, newValue) +#define ODEMX_OBS_T(ObserverType, Event) +#define ODEMX_OBS_ATTR_T(ObserverType, Attribute, oldValue, newValue) + +#endif /* ODEMX_USE_OBSERVATION */ + +} } // namespace odemx::data + +#endif /* ODEMX_OBSERVABLE_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/Producer.h b/odemx-lite/include/odemx/data/Producer.h new file mode 100644 index 0000000000000000000000000000000000000000..c1c96ed086371502b1d4118a0683542a9d68bf60 --- /dev/null +++ b/odemx-lite/include/odemx/data/Producer.h @@ -0,0 +1,269 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file data/Producer.h + * @author Ronald Kluth + * @date created at 2009/03/18 + * @brief Declaration of class odemx::data::Producer + * @sa Producer.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_PRODUCER_INCLUDED +#define ODEMX_DATA_PRODUCER_INCLUDED + +#include <odemx/setup.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/SimRecord.h> +#include <odemx/data/Label.h> + +#include <CppLog/Producer.h> + +namespace odemx { + +//----------------------------------------------------------forward declarations + +namespace base { class Simulation; } + +//-----------------------------------------------------------header declarations + +namespace data { + +/** + * @brief Producer base type that enables managed ODEMx log channels + * @since 3.0 + * + * The logging library included in ODEMx provides a configurable Producer + * template. By passing the IDs of channels (created with macro + * ODEMX_DECLARE_DATA_CHANNEL) as Arguments to the template parameter + * Enable, the producer class receives shared_ptr members which are + * initialized automatically during construction by the logging manager. + */ +typedef Log::Producer< + Log::Enable< + channel_id::trace, + channel_id::debug, + channel_id::info, + channel_id::warning, + channel_id::error, + channel_id::fatal, + channel_id::statistics + > + > ProducerBase; + +/** + * @brief Base class for all log-producing classes in ODEMx + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::LoggingManager, ODEMX_DECLARE_DATA_CHANNEL + * + * The class odemx::data::Producer is the base class for all ODEMx components + * that produce log records. This includes statistics producers. It is + * primarily responsible for enabling access to the log channels that ODEMx + * provides by default: + * @li trace + * @li debug + * @li info + * @li warning + * @li error + * @li fatal + * @li statistics + * + * All of those channels use the record type @c odemx::data::SimRecord. + * Access to the channels is automatically provided within subclasses of + * this class. Channel initialization is based on the cooperation of + * producer objects with the logging manager. + * + * Objects of class odemx::data::Producer are uniquely labeled within one + * simulation context because all data producers must request a label from + * the logging manager, which is a base class of odemx::base::Simulation. + * Uniqueness of labels is ensured by appending numbers if a particular label + * already exists within the name scope. + * + * @note This class replaces the interfaces LabeledObject and TraceProducer + * from previous versions of ODEMx. + */ +class Producer +: public ProducerBase +{ +public: + /// Destruction + virtual ~Producer(); + + /** + * @brief Enable logging for one producer object + * @see disableLogging + * + * The functionality of enabling and disabling log channels is based on + * shared_ptr members. If the pointer is set, logging is active. Otherwise, + * all logging statements involving a disabled channel are ignored. This + * method reactivates previously disabled log channels. + * + * @note By default, ODEMx logging functionality is enabled for all producers. + * @note The channels @c warning, @c error, and @c fatal are always active. + */ + void enableLogging(); + + /** + * @brief Disable logging for one producer object + * @see enableLogging + * + * Disabling the logging functionality means resetting the shared_ptr + * members which reference the log channels. When sucha pointer is not + * set all logging statements involving that channel are ignored. + * + * @note This only affects the channels @c trace, @c debug, @c info, and + * @c statistics. The channels @c warning, @c error, and @c fatal are + * always active. + */ + void disableLogging(); + + /// Get the unique label of the object, used for logging and filtering sender names. + const Label& getLabel() const; + + /// Get the real type of the object. This is useful for logging and filtering sender types + const TypeInfo getType() const; + + /// Get a const reference to the simulation context + const base::Simulation& getSimulation() const; + + /// Get a non-const Reference to the simulation context + base::Simulation& getSimulation(); + +protected: + /// Construction for subclasses only + Producer( base::Simulation& sim, const Label& label ); + + /** + * @brief Convenience method to create log records with required parameters + * + * Using this method is the preferred way of creating log records within + * producer classes. Users need only provide the text message of the record + * and additional data such as simulation context, time, and sender + * is added automatically. + * + * Usage: + * @code + * info << log( "some simulation event" ); + * @endcode + */ + SimRecord log( const StringLiteral& text ) const; + + /** + * @name Statistics convenience methods + * + * Statistical records in ODEMx fall within one of four categories: + * @li countable statistics events + * @li updated sequences of numbers + * @li parameters to be logged only once + * @li reset of accumulated data + * + * The following methods provide quick access to the creation of + * adequate log records for each category. + * @{ + */ + /** + * @brief Log a countable statistics event + * @param name Name of the counted property + * @param value Amount to add to the counter, default is 1 + * @return A log record with text "count" and a detail pair of @c name and @c value + */ + SimRecord count( const StringLiteral& name, std::size_t value = 1 ) const; + + /** + * @brief Log a parameter of a statistics producer + * @tparam ValueT Type of the parameter value + * @param name Name of the parameter + * @param value Value of the parameter, can be of arbitrary simple type + * @return A record with text "parameter" and a detail pair of @c name and @c value + */ + SimRecord param( const StringLiteral& name, const std::string& value ) const + { + return log( "parameter" ).detail( name, value ); + } + + template < typename ValueT > + SimRecord param( const StringLiteral& name, ValueT value ) const + { + return log( "parameter" ).detail( name, std::to_string(value) ) ; + } + + // old definition - now unsupported + /* + template < typename ValueT > + SimRecord param( const StringLiteral& name, ValueT value ) const + { + return log( "parameter" ).detail( name, value ); + } + */ + + /** + * @brief Log a record for a sequence of numbers + * @note This method only accepts doubles now. This was done because after switching + * DynamicVar to a POCO-independent type, it doesn't support runtime conversion + * any longer. + * @param name Name of the updated property + * @param value Value of the current update, must be a numeric type + * @return A record with text "update" and a detail pair of @c name and @c value + */ + SimRecord update( const StringLiteral& name, double value ) const + { + return log( "update" ).detail( name, value ); + } + + // old definition - now unsupported + /* + template < typename ValueT > + SimRecord update( const StringLiteral& name, ValueT value ) const + { + return log( "update" ).detail( name, value ); + } + */ + + /** + * @brief Log a statistics reset + * @return A record with text "reset" and no additional details + */ + SimRecord reset() const; + //@} + +private: + /// Pointer to the simulation context + base::Simulation* sim_; +}; + +/** + * @brief Global ostream inserter overload for data producer references + * + * This makes all data producers string-streamable by writing their label + * to the stream. + */ +extern std::ostream& operator<<( std::ostream& os, const Producer& obj ); + +/** + * @brief Global ostream inserter overload for data producer pointers + * + * This operator overload also writes the label of a data producer to the stream. + */ +extern std::ostream& operator<<( std::ostream& os, const Producer* obj ); + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_PRODUCER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/Report.h b/odemx-lite/include/odemx/data/Report.h new file mode 100644 index 0000000000000000000000000000000000000000..ec5cea4313299efe50e120736a222a67c7d224bc --- /dev/null +++ b/odemx-lite/include/odemx/data/Report.h @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002 - 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Report.h + * @author Ralf Gerstenberger + * @date created at 2002/06/21 + * @brief Declaration of class odemx::data::Report + * @sa Report.cpp + * @since 1.0 + */ + +#ifndef ODEMX_DATA_REPORT_INCLUDED +#define ODEMX_DATA_REPORT_INCLUDED + +#include <odemx/data/ReportTable.h> + +#include <set> +#include <string> +#include <vector> + +//----------------------------------------------------------forward declarations +namespace odemx { +namespace data { + +class ReportProducer; + +//-----------------------------------------------------------header declarations + +/** + \ingroup data + + \author Ralf Gerstenberger + + \brief Base class for special report objects + + \sa ReportTable ReportProducer + + Report is the base class for user defined report objects. + Report manages ReportTables, ReportProducers and the report generation. + Each Report object represents an individual report. There can be + multiple reports in a simulation. + + \since 1.0 +*/ +class Report { +public: + + /// Destruction + virtual ~Report(); + + /// \name Reporter handling + //@{ + /// Add a reporter to this Report + void addReportProducer( ReportProducer& reporter ); + /// Remove a reporter from this Report + void removeReportProducer( ReportProducer& reporter ); + //@} + + /// @name ReportTable handling + //@{ + /** + \brief Create or retrieve a suitable table by name and definition + + \param name + name of new Table + \param def + TableDefinition of new Table + + \return new Table + + \note If there is already a Table with an equal name and + definition it will be returned instead of creating a new Table. + */ + ReportTable& getTable( const std::string& name, const ReportTable::Definition& def ); + + /** + \brief generate report by getting data from ReportProducers + + Report generation: + @li call all registered ReportProducer objects + @li call processTables + */ + void generateReport(); + +protected: + /** + \brief find a Table + + \param name + name of Table + \param def + TableDefinition of Table + + \return found Table or 0 + */ + ReportTable* findTable( const std::string& name, const ReportTable::Definition& def ) const; + /** + * @brief Allows defining some actions before the tables get processed + * + * The idea is to give Report specializations a means to do some pre- + * and some post-processing. This can useful for XML output, for example, + * where one might want to start a document. + */ + virtual void startProcessing() {}; + + /** + \brief Process arbitrary tables for output + + Report objects have to provide a meaningful processTables() function. + This method is responsible for transforming tables from ReportProducers + into some output format such as plain text or XML. + */ + virtual void processTables() = 0; + + /** + * @brief Allows defining some actions after the tables got processed + * + * This method provides the oportunity to do post-processing. + * This can useful for XML output, for example where one might want + * to properly close a document. + */ + virtual void endProcessing() {}; + //@} + + /// Vector type to store pointers to generated tables + typedef std::vector< ReportTable* > TableVec; + /// Vector type to store pointers to registered producers + typedef std::set< ReportProducer* > ReportProducerSet; + + /// Contained tables + TableVec tables_; + /// Associated reporters + ReportProducerSet producers_; +}; + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_REPORT_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/ReportProducer.h b/odemx-lite/include/odemx/data/ReportProducer.h new file mode 100644 index 0000000000000000000000000000000000000000..b500253c8aa372644bc570af88b276f8c883f911 --- /dev/null +++ b/odemx-lite/include/odemx/data/ReportProducer.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002 - 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ReportProducer.h + * @author Ralf Gerstenberger + * @date created at 2002/06/21 + * @brief Declaration of class odemx::data::ReportProducer + * @sa ReportProducer.cpp + * @since 1.0 + */ + +#ifndef ODEMX_DATA_REPORTER_INCLUDED +#define ODEMX_DATA_REPORTER_INCLUDED + +#include <odemx/data/Label.h> +#include <CppLog/NamedElement.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { + +namespace base { class Simulation; } + +namespace data { + +class Report; + +//-----------------------------------------------------------header declarations + +/** \ingroup data + + \author Ralf Gerstenberger + + \brief A ReportProducer generates data in the form of tables. + + \sa Report ReportTable + + A ReportProducer implementation generates data for reports. + It has to implement the pure virtual function report. + + \since 1.0 +*/ +class ReportProducer +: public Log::NamedElement +{ +public: + /// Construction with user-defined simulation context + ReportProducer( base::Simulation& sim, const Label& label ); + /// Destruction + virtual ~ReportProducer(); + /// Get the label of the report producer for display in a table column + const Label& getLabel() const; + /** + \brief report generation + + This function is called by a Report object during report generation. + A ReportProducer implementation implements this method to + provide its data. ReportProducer can be associated to one or + more Report objects. A ReportProducer will contribute to each + Report it is associated to. + */ + virtual void report( Report& report ) = 0; +}; + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_REPORTER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/ReportTable.h b/odemx-lite/include/odemx/data/ReportTable.h new file mode 100644 index 0000000000000000000000000000000000000000..0f7645946082f60bdcebdcf9b1bcd98282f422ac --- /dev/null +++ b/odemx-lite/include/odemx/data/ReportTable.h @@ -0,0 +1,360 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ReportTable.h + * @author Ronald Kluth + * @date created at 2009/12/17 + * @brief Declaration of class odemx::data::ReportTable + * @sa ReportTable.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_REPORTTABLE_INCLUDED +#define ODEMX_DATA_REPORTTABLE_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/data/Label.h> +#include <vector> + +namespace odemx { +namespace data { + +/** + * @brief Container for accumulated data collected from ReportProducers + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see Report ReportProducer + * + * All data are reported in tables. The structure of a table is defined + * by a table definition. A table cannot be created manually. To get a table + * object, the user has to request one from a Report object. + */ +class ReportTable +{ +public: + + /** + * @brief Provides column label and type describing column data + * + * All columns in tables are associated to a data type like integer, + * real values or strings, and sometimes represent graphical bars. + */ + class Column { + public: + /// Destruction + virtual ~Column() {} + + /// Enumeration of the allowed column types in tables + enum Type { + INTEGER, ///< integer numbers + REAL, ///< real numbers + STRING, ///< text + BAR, ///< graphical representation + SIMTIME, ///< used for SimTime + INVALID ///< used for undefined columns + }; + + /// Each column must know its caption label + const Label& getLabel() { return label_; } + /// Each column must know its type + Type getType() { return type_; } + /// Get a string representation of the given column type + static const std::string typeToString( Type type ); + + protected: + /// Construction + Column( const Label& label, Type type ): label_( label ), type_( type ) {} + + private: + /// Each column has a label for the table captions + Label label_; + /// Each column knows its type + Type type_; + }; + + + /** + * @brief Representation of a table column that stores data in a vector + * + * ColumnT is the class that stores all table data. It requires a + * label and a column type to be given during construction. + */ + template < typename DataType > + class ColumnT: public Column { + public: + /// Destructor + virtual ~ColumnT() {} + + protected: + friend class ReportTable; + + friend ReportTable& operator<<( ReportTable& t, long d ); + friend ReportTable& operator<<( ReportTable& t, long long d ); + friend ReportTable& operator<<( ReportTable& t, double d ); + friend ReportTable& operator<<( ReportTable& t, const std::string& s ); + + friend ReportTable& operator>>( ReportTable& t, long& to ); + friend ReportTable& operator>>( ReportTable& t, long long& to ); + friend ReportTable& operator>>( ReportTable& t, unsigned long long& to ); + friend ReportTable& operator>>( ReportTable& t, double& to ); + friend ReportTable& operator>>( ReportTable& t, std::string& to ); + + /// Size type used for column indices + typedef typename std::vector< DataType >::size_type SizeType; + + /// Constructor, to be called by Table class only + ColumnT( const Label& label, Type type ): Column( label, type ) {} + + /// Append data to column, i.e. add content of next line in table + void addData( DataType d ) { data.push_back( d ); } + + /// Read data from column, the given line is range-checked and may throw std::out_of_range + const DataType& getData( SizeType line ) const + { + return data.at( line ); + } + private: + /// stores the column data, index represents lines in the Table + std::vector< DataType > data; + }; + + /** + * @brief This class is used to build table definitions at runtime + */ + class Definition + { + public: + /** + * @brief Control codes used for operator << input into tables + */ + enum ControlCode + { + ENDL, ///< end of table line + TAB ///< skip column + }; + + /// Size type used for column indices + typedef std::vector< std::string >::size_type SizeType; + + /// Get the number of table columns + SizeType getNumberOfColumns() const; + /// Get the label of column @c index + const std::string& getLabelOfColumn( SizeType index ) const; + /// Get the type of column @c index + Column::Type getTypeOfColumn( SizeType index ) const; + + /** + \brief Add columns to the table definition + \param label column label + \param type column type + Use addColumn() to build a TableDefinition. + */ + void addColumn( const std::string& label, Column::Type type ); + + private: + std::vector< std::string > columnLabels_; ///< column labels + std::vector< Column::Type > columnTypes_; ///< column types + }; + + /// Size type used for table indices + typedef Definition::SizeType SizeType; + + /// Stores a Table input or output position when streaming data + struct Position + { + Position(): col( 0 ), line( 0 ) {} + SizeType col; + SizeType line; + }; + + /// Construction is managed by Report + ReportTable( const Label& label, const Definition& def ); + + /// Destruction is managed by Report + ~ReportTable(); + + /// \name Table attributes + //@{ + /// Get the name of the table + const Label& getLabel() const { return label_; } + /// Get the table definition + const Definition& getDefinition() const { return def_; } + + /** + * @brief Get number of lines in the table + * + * @note This function returns the number of completely filled lines. + * To finish a line, use Definition::ControlCode. + */ + SizeType getNumberOfLines() const { return lineCount_; } + + /// Get the number of columns in a table + SizeType getNumberOfColumns() const { return columns_.size(); } + + /// Get a specific column label by index + const std::string& getLabelOfColumn( SizeType index ) const + { + return columns_.at( index )->getLabel(); + } + + /// Get a specific column type by index + Column::Type getTypeOfColumn( SizeType index ) const + { + return columns_.at( index )->getType(); + } + //@} + + /** + \name Input streaming + + The data can be entered into a table in a streaming like fashion. + The data type has to match the column type. A ControlCode can be + used to skip columns or the rest of a line. Skipped columns are + filled with default data <tt>(0, 0.0, "")</tt>. + + @{ + */ + friend ReportTable& operator<<( ReportTable& t, int d ); + friend ReportTable& operator<<( ReportTable& t, unsigned int d ); + friend ReportTable& operator<<( ReportTable& t, long d ); + friend ReportTable& operator<<( ReportTable& t, long long d ); + friend ReportTable& operator<<( ReportTable& t, unsigned long d ); + friend ReportTable& operator<<( ReportTable& t, unsigned long long d ); + friend ReportTable& operator<<( ReportTable& t, float d ); + friend ReportTable& operator<<( ReportTable& t, double d ); + friend ReportTable& operator<<( ReportTable& t, const std::string& d ); + friend ReportTable& operator<<( ReportTable& t, const char* d ); + friend ReportTable& operator<<( ReportTable& t, Definition::ControlCode d ); + //@} + + /** + \name Output streaming + + The data of a table can be read in a streaming like fashion. + The data type has to match the column type. + @{ + */ + friend ReportTable& operator>>( ReportTable& t, long& to ); + friend ReportTable& operator>>( ReportTable& t, long long& to ); + friend ReportTable& operator>>( ReportTable& t, unsigned long long& to ); + friend ReportTable& operator>>( ReportTable& t, double& to ); + friend ReportTable& operator>>( ReportTable& t, std::string& to ); + //@} + + /** + \name Output random access + + Get the data of a specific table cell + + @{ + */ + /** + \brief Get SIMTIME value from field (\p col, \p line). + \note Column col must be a SIMTIME column. + */ + base::SimTime getSIMTIME( SizeType col, SizeType line ); + + /** + \brief Get graphical BAR value from field (\p col, \p line). + \note Column col must be a BAR column. + */ + long getBAR(SizeType col, SizeType line ); + + /** + \brief Get INTEGER value from field (\p col, \p line). + \note Column col must be an INTEGER column. + */ + long getINTEGER(SizeType col, SizeType line ); + + /** + \brief Get REAL value from field (\p col, \p line). + \note Column col must be an INTEGER or a REAL column. + */ + double getREAL(SizeType col, SizeType line ); + + /** + \brief Get a STRING value from field (\p col, \p line). + \note Type conversion from BAR, INTEGER and REAL to STRING + is done if required. + */ + std::string getSTRING( SizeType col, SizeType line ); + //@} + + /// Get the current input column to add data + Column* getCurrentInputColumn() + { + return columns_.at( inputPosition_.col ); + } + /// Get the current output column to read data from + Column* getCurrentOutputColumn() + { + return columns_.at( outputPosition_.col ); + } + /// Get the index of the current output streaming line + SizeType getOutputLine() { return outputPosition_.line; } + + /// Add a default value (0, 0.0, "", 0) to the column + void addDefaultValue(); + +private: + /// Increment input pointer for streaming, change line if necessary + void advanceInputPosition(); + /// Increment output pointer for streaming, change line if necessary + void advanceOutputPosition(); + + friend class Report; + /// Vector type for storing pointers to table columns + typedef std::vector< Column* > ColumnVec; + + Label label_; ///< table label + Definition def_; ///< table definition + SizeType lineCount_; /// size of table + ColumnVec columns_; ///< vector containing pointers to columns + Position inputPosition_; ///< input streaming position pointer + Position outputPosition_; ///< output streaming position pointer +}; + +extern ReportTable& operator<<( ReportTable& t, int d ); ///< enter int value +extern ReportTable& operator<<( ReportTable& t, unsigned int d ); ///< enter unsigned int value +extern ReportTable& operator<<( ReportTable& t, long d ); ///< enter long value +extern ReportTable& operator<<( ReportTable& t, long long d ); ///< enter long long value +extern ReportTable& operator<<( ReportTable& t, unsigned long d ); ///< enter unsigned long value +extern ReportTable& operator<<( ReportTable& t, unsigned long long d ); ///< enter unsigned long long value +extern ReportTable& operator<<( ReportTable& t, float d ); ///< enter float value +extern ReportTable& operator<<( ReportTable& t, double d ); ///< enter double value +extern ReportTable& operator<<( ReportTable& t, const std::string& d ); ///< enter std::string value +extern ReportTable& operator<<( ReportTable& t, const char* d ); ///< enter const char* value +extern ReportTable& operator<<( ReportTable& t, ReportTable::Definition::ControlCode d ); ///< enter control codes + +extern ReportTable& operator>>( ReportTable& t, long& to ); ///< read long value +extern ReportTable& operator>>( ReportTable& t, long long& to ); ///< read long long value +extern ReportTable& operator>>( ReportTable& t, unsigned long long& to ); ///< read unsigned long long value +extern ReportTable& operator>>( ReportTable& t, double& to ); ///< read double value +extern ReportTable& operator>>( ReportTable& t, std::string& to ); ///< read std::string value + +/** + * @brief Compare two table definitions, used for grouping ReportProducer results in the same table + * @return @c true if number of columns, all labels and all types are equal + */ +extern bool operator==( const ReportTable::Definition& lhs, const ReportTable::Definition& rhs ); + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_REPORTTABLE_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/SimRecord.h b/odemx-lite/include/odemx/data/SimRecord.h new file mode 100644 index 0000000000000000000000000000000000000000..2fa7318597e7333cbf73a4ca43d5d90bfad5afce --- /dev/null +++ b/odemx-lite/include/odemx/data/SimRecord.h @@ -0,0 +1,429 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimRecord.h + * @author Ronald Kluth + * @date created at 2009/03/16 + * @brief Declaration of class odemx::data::SimRecord + * @sa SimRecord.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_SIMRECORD_INCLUDED +#define ODEMX_DATA_SIMRECORD_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/data/TableKey.h> +#include <odemx/data/TypeInfo.h> +#include <odemx/data/Label.h> +#include <odemx/util/StringConversion.h> +#include <CppLog/Record.h> +#include <CppLog/DeclareInfoType.h> + +#include <vector> +#include <utility> +#include <type_traits> +#include <typeinfo> +#include <tuple> + +namespace odemx { + +//----------------------------------------------------------forward declarations + +namespace base { class Simulation; } + +namespace data { + +class Producer; + +//-----------------------------------------------------------header declarations + +/**@brief Variable type that can hold and convert many different types. + * @ingroup data + * @author Dorian Weber + * @since ODEMx-lite-1.0 (based on ODEMx-3.0) + * + * This is essentially an implementation of the Boost::Any-Type for ODEMx. It + * replaces the Dynamic::Var-Type of the POCO-library that was used before. + * Unfortunately, this type had internal conversion capabilities that were not + * reproduced with this implementation, so bugs were introduced into the report + * mechanism that will hopefully be resolved completely with Alexander Walthers + * upcoming work. + */ +class DynamicVar +{ + template <typename T> + using decay = typename std::decay<T>::type; + + template <typename T> + using none = typename std::enable_if<!std::is_same<DynamicVar, T>::value>::type; + + struct base + { + virtual ~base() { } + virtual bool is(const std::type_info& i) const = 0; + virtual base* clone() const = 0; + } *p; + + template <typename T> + struct data : base, std::tuple<T> + { + using std::tuple<T>::tuple; + + T& get()& { return std::get<0>(*this); } + + T const& get() const& { return std::get<0>(*this); } + + bool is(const std::type_info& i) const override { return i == typeid(T); } + base* clone() const override { return new data{get()}; } + }; + + template <typename T> + T &stat() { return static_cast<data<T>&>(*p).get(); } + + template <typename T> + T const &stat() const { return static_cast<data<T> const&>(*p).get(); } + + template <typename T> + T &dyn() { return dynamic_cast<data<T>&>(*p).get(); } + + template <typename T> + T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); } + +public: + DynamicVar(): p() { } + ~DynamicVar() { delete p; } + + DynamicVar(DynamicVar&& s) : p{s.p} { s.p = nullptr; } + DynamicVar(DynamicVar const& s) : p{s.p->clone()} { } + + template <typename T, typename U = decay<T>, typename = none<U>> + DynamicVar(T&& x) : p{new data<U>{std::forward<T>(x)}} { } + + DynamicVar& operator=(DynamicVar s) { swap(*this, s); return *this; } + + friend void swap(DynamicVar& s, DynamicVar& r) { std::swap(s.p, r.p); } + + void clear() { delete p; p = nullptr; } + + bool empty() const { return p; } + + template <typename T> + bool is() const { return p ? p->is(typeid(T)) : false; } + + template <typename T> + T&& cast() && { return std::move(dyn<T>()); } + template <typename T> + T& cast() & { return dyn<T>(); } + template <typename T> + T const& cast() const& { return dyn<T>(); } + + template <typename T> + T&& as() && { return std::move(stat<T>()); } + template <typename T> + T& as() & { return stat<T>(); } + template <typename T> + T const& as() const& { return stat<T>(); } + + template <typename T> + operator T&&() && { return as<T>(); } + template <typename T> + operator T&() & { return as<T>(); } + template <typename T> + operator T const&() const& { return as<T>(); } +}; + +// typedef std::experimental::any DynamicVar; // changed in odemx-line from Poco::DynamicVar +/// String literal wrapper type +typedef Log::StringLiteral StringLiteral; + +/** + * @brief Record type used for logging ODEMx simulation data + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::Producer + * + * Starting with Version 3.0 ODEMx is based on a separate logging library + * to provide for tracing, debug and error output. The record type of the + * logging components is configurable. With this class, ODEMx provides its + * own class type for logging information. + * + * SimRecord objects usually describe one notable simulation event, which is + * given as a short text message. Other than that, objects of this type always + * transport information about the sender, the simulation context and the + * simulation time. Optionally, a class scope can be attached, and an arbitrary + * number of details can be provided in the form of name-value-pairs. + * + * Usage within a producer class: + * @code + * channel << log( "some event" ).detail( "name", value ).scope( typeid(ClassName) ) + * @endcode + * + * The channel is usually one of the seven log channels provided by ODEMx + * (see odemx::data::LoggingManager). The method log creates a SimRecord object + * with the aformentioned data, and the methods detail and scope can be chained + * together in order to add more information to the log record. + */ +class SimRecord +{ +public: + /// Vector type for pairs of names and values of various types + typedef std::vector< std::pair< StringLiteral, DynamicVar > > DetailVec; + + /** + * @brief Construction + * @param sim The simulation context + * @param sender The sender of the log record + * @param text A description of the simulation event + * + * SimRecord objects are meant to be created within classes derived from + * odemx::data::Producer. Therefore, these log records are usually not + * constructed directly because the class Producer provides several + * convenience methods to deal with the task. + */ + SimRecord( const base::Simulation& sim, const Producer& sender, + const StringLiteral& text ); + + /// Destruction + virtual ~SimRecord(); + + /// Get the text message of the record + const StringLiteral& getText() const; + /// Get the simulation context the record originated from + const base::Simulation& getSimulation() const; + /// Get a reference to the sender object of the record + const Producer& getSender() const; + /// Get the simulation time at which the record was created + base::SimTime getTime() const; + /// Get the class scope from which the record was sent + const TypeInfo& getScope() const; + /// Get a vector containing additional details as name-value pairs + const DetailVec& getDetails() const; + /// Get a @c shared_ptr referencing the detail vector + const std::shared_ptr< DetailVec > getDetailPointer() const; + + /// Check whether the class scope of the record is set + bool hasScope() const; + /// Store the class scope from which this record was sent + SimRecord& scope( const TypeInfo& type ); + + /// Check whether the record carries additional details + bool hasDetails() const; + /// Add a detail pair consisting of a name and a value + template < typename ValueT > + SimRecord& detail( const StringLiteral& name, const ValueT& value ) + { + if( ! details_ ) + { + initDetailVec(); + } + details_->push_back( DetailVec::value_type( name, value ) ); + return *this; + } + /// Store two details at once, i.e. pairs for the old and the new value + template< typename ValueT > + SimRecord& valueChange( const ValueT& oldVal, const ValueT& newVal ) + { + if( ! details_ ) + { + initDetailVec(); + } + details_->push_back( DetailVec::value_type( "old value", oldVal ) ); + details_->push_back( DetailVec::value_type( "new value", newVal ) ); + return *this; + } + +private: + /// Stores the text message of this record + StringLiteral text_; + /// Pointer to the simulation context of the record + const base::Simulation* sim_; + /// Pointer to the sender object of the record + const Producer* sender_; + /// Simulation time at which the record was created + base::SimTime time_; + /// Class scope the record originated from + TypeInfo scope_; + /// Stores name-value pairs containing additional record details + std::shared_ptr< DetailVec > details_; + +private: + /// Initialize the shared_ptr holding the detail vector + void initDetailVec(); +}; + +} } // namespace odemx::data + +/* +// necessary specialization for DynamicVar to handle long long SimTime as detail value +namespace Poco { +namespace Dynamic { + +template <> +class VarHolderImpl<long long>: public VarHolder +{ +public: + VarHolderImpl(long long val): _val(val) + { + } + + ~VarHolderImpl() + { + } + + const std::type_info& type() const + { + return typeid(long long); + } + + void convert(Int8& val) const + { + convertToSmaller(_val, val); + } + + void convert(Int16& val) const + { + convertToSmaller(_val, val); + } + + void convert(Int32& val) const + { + convertToSmaller(_val, val); + } + + void convert(Int64& val) const + { + convertToSmaller(_val, val); + } + + void convert(UInt8& val) const + { + convertSignedToUnsigned(_val, val); + } + + void convert(UInt16& val) const + { + convertSignedToUnsigned(_val, val); + } + + void convert(UInt32& val) const + { + convertSignedToUnsigned(_val, val); + } + + void convert(UInt64& val) const + { + convertSignedToUnsigned(_val, val); + } + + void convert(bool& val) const + { + val = (_val != 0); + } + + void convert(float& val) const + { + val = static_cast<float>(_val); + } + + void convert(double& val) const + { + val = static_cast<double>(_val); + } + + void convert(char& val) const + { + UInt8 tmp; + convert(tmp); + val = static_cast<char>(tmp); + } + + void convert(std::string& val) const + { + val = odemx::toString( _val ); + //val = NumberFormatter::format(_val); + } + + void convert(DateTime& dt) const + { + dt = Timestamp(_val); + } + + void convert(LocalDateTime& ldt) const + { + ldt = Timestamp(_val); + } + + void convert(Timestamp& val) const + { + val = Timestamp(_val); + } + + VarHolder* clone() const + { + return new VarHolderImpl(_val); + } + + const long long& value() const + { + return _val; + } + + bool isArray() const + { + return false; + } + + bool isStruct() const + { + return false; + } + + bool isInteger() const + { + return std::numeric_limits<long long>::is_integer; + } + + bool isSigned() const + { + return std::numeric_limits<long long>::is_signed; + } + + bool isNumeric() const + { + return std::numeric_limits<long long>::is_specialized; + } + + bool isString() const + { + return false; + } + +private: + VarHolderImpl(); + VarHolderImpl(const VarHolderImpl&); + VarHolderImpl& operator = (const VarHolderImpl&); + + long long _val; +}; + +} } // namespace Poco::Dynamic +*/ +#endif /* ODEMX_DATA_SIMRECORD_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/SimRecordFilter.h b/odemx-lite/include/odemx/data/SimRecordFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..5bab29a7cc6004150428dca80ade84281a520254 --- /dev/null +++ b/odemx-lite/include/odemx/data/SimRecordFilter.h @@ -0,0 +1,254 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimRecordFilter.h + * @author Ronald Kluth + * @date created at 2009/03/18 + * @brief Declaration of class odemx::data::SimRecordFilter + * @sa SimRecordFilter.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_SIMRECORDFILTER_INCLUDED +#define ODEMX_DATA_SIMRECORDFILTER_INCLUDED + +#include <odemx/data/Producer.h> +#include <CppLog/Filter.h> + +namespace Log { + +/** + * @brief Specialization of class template Filter for simulation records + * + * This template specialization implements the functionality used by the + * class SimRecordFilter. The filtering is based on the concept of filter sets, + * meaning that users can add values in several categories, which are checked + * for matching values in SimRecord objects. For example, one might want to + * filter by producer type and hence adds the typeid of that specific class. + * All record originating from objects of that class will then match that + * entry in the filter set. + * + * However, matching records are not necessarily filtered out because the + * filter supports two different modes: pass all / pass none. In the first + * case, all records may pass, except those with a match, while in the second + * case all records are blocked and only those that match filter sets may pass. + */ +template <> +class Filter< odemx::data::SimRecord > +{ +public: + /// Construction + Filter() + : isSet_( false ) + , passAll_( true ) + {} + + /// Destruction + virtual ~Filter() {} + + /// Only filter out the log records matched by the filter + void passAll() + { + isSet_ = true; + passAll_ = true; + } + + /// Filter out all log records except those matched by the filter + void passNone() + { + isSet_ = true; + passAll_ = false; + } + + /** + * @brief Add record text values to the filter + * + * @note The method returns a set inserter object that offers a + * streaming operator overload (<<) so that several values can be + * added in one call. + * + * Usage: + * @code + * filter->addRecordText() << "create" << "destroy"; + * @endcode + */ + Detail::SetInserter< StringLiteral > addRecordText() + { + // remember that the filter has been initialized + isSet_ = true; + return Detail::SetInserter< StringLiteral >( recordTexts_ ); + } + + /** + * @brief Add producer labels to filter out log data from specific sender objects + * @note The method also returns a set inserter object for streaming values. + * @see addRecordText + */ + Detail::SetInserter< odemx::data::Label > addProducerLabel() + { + // remember that the filter has been initialized + isSet_ = true; + return Detail::SetInserter< odemx::data::Label >( senderLabels_ ); + } + + /** + * @brief Add producer type IDs to filter out log records from specific classes + * @note The method returns a set inserter object for streaming type IDs. + * + * Usage: + * @code + * filter->addProducerType() << typeid(SomeProcess) << typeid(SomeEvent); + * @endcode + */ + Detail::SetInserter< odemx::data::TypeInfo > addProducerType() + { + // remember that the filter has been initialized + isSet_ = true; + return Detail::SetInserter< odemx::data::TypeInfo >( senderTypes_ ); + } + + /** + * @brief Add type IDs to filter out log records from specific class scopes + * @note The method also returns a set inserter object for streaming type IDs. + * @see addProducerType + * + * This is particularly useful for filtering in class hierarchies. + * For example, on might not want to see records produced by a base + * class. This method makes it possible to filter these out as long as + * base class provides scope infomation with its records. All ODEMx + * components do. + */ + Detail::SetInserter< odemx::data::TypeInfo > addRecordScope() + { + // remember that the filter has been initialized + isSet_ = true; + return Detail::SetInserter< odemx::data::TypeInfo >( recordScopes_ ); + } + + /// Reset filter to default values, which effectively disables it + void resetFilter() + { + senderLabels_.clear(); + senderTypes_.clear(); + recordScopes_.clear(); + recordTexts_.clear(); + isSet_ = false; + passAll_ = true; + } + + /** + * @brief This method implements the filter interface + * @param record The currently processed log record + * @return true if the record may pass the filter, false otherwise + * + * If the filter is not set, all records may pass. Otherwise, all four + * filter sets are checked for matching values. Should the record contain + * at least one value that is also stored in a filter set, it further + * depends on the filter mode whether the record may pass, in which case + * the method returns @c true. + */ + bool pass( const odemx::data::SimRecord& record ) const + { + if( ! isSet_ ) + { + return true; + } + + const odemx::data::Producer& sender = record.getSender(); + + // check the record text, sender label, sender type and record scope + if( recordTexts_.find( record.getText() ) != recordTexts_.end() + || senderLabels_.find( sender.getLabel() ) != senderLabels_.end() + || senderTypes_.find( sender.getType() ) != senderTypes_.end() + || recordScopes_.find( record.getScope() ) != recordScopes_.end() ) + { + // match found, the record may only pass if passAll_ is false + return ! passAll_; + } + + // no match found, passing depends on pass mode only + return passAll_; + } + +protected: + /// Stores whether the filter is active, i.e. contains filter values or uses pass none + bool isSet_; + /// Stores the filter mode, the default is pass all + bool passAll_; + /// Stores text values to be matched when filtering records + std::set< StringLiteral > recordTexts_; + /// Stores sender labels to match for filtering + std::set< odemx::data::Label > senderLabels_; + /// Stores type IDs to filter by record sender type + std::set< odemx::data::TypeInfo > senderTypes_; + /// Stores type IDs for filtering records by the class scope they originated from + std::set< odemx::data::TypeInfo > recordScopes_; +}; + +} // namespace Log + +namespace odemx { +namespace data { + +/** + * @brief Specialized filter class that can handle SimRecord objects + * + * The functionality of this class is provided by the template specialization + * Log::Filter<SimRecord>. The filtering is based on the concept of filter sets, + * meaning that users can add values in several categories, which are checked + * for matching values in SimRecord objects. For example, one might want to + * filter by producer type and hence adds the typeid of that specific class. + * All record originating from objects of that class will then match that + * entry in the filter set. + * + * However, matching records are not necessarily filtered out because the + * filter supports two different modes: pass all / pass none. In the first + * case, all records may pass, except those with a match, while in the second + * case all records are blocked and only those that match filter sets may pass. + * + * Usage: + * @code + * filter->addRecordText() << "create" << "destroy"; + * filter->addProducerType() << typeid(SomeClass); + * filter->addProducerLabel() << "DefaultSimulation"; + * filter->addRecordScope() << typeid(Process) << typeid(Event); + * @endcode + * + * @see Log::Filter<SimRecord> + */ +class SimRecordFilter +: public Log::Filter< SimRecord > +{ +public: + /// Creation via static method to enforce shared_ptr-usage + static std::shared_ptr< SimRecordFilter > create(); + /// Destruction + virtual ~SimRecordFilter(); + +protected: + /// Construction private, use create instead + SimRecordFilter(); +}; + +/// Pointer type to manage SimRecordFilter objects +typedef std::shared_ptr< SimRecordFilter > SimRecordFilterPtr; + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_SIMRECORDFILTER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/TableKey.h b/odemx-lite/include/odemx/data/TableKey.h new file mode 100644 index 0000000000000000000000000000000000000000..3daa0a31adf21a93bd158c9b91ca96a77edb3b86 --- /dev/null +++ b/odemx-lite/include/odemx/data/TableKey.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TableKey.h + * @author Ronald Kluth + * @date created at 2009/09/14 + * @brief Declaration of type odemx::data::TableKey + * @since 3.0 + */ + +#ifndef ODEMX_DATA_TABLEKEY_INCLUDED +#define ODEMX_DATA_TABLEKEY_INCLUDED + +namespace odemx { +namespace data { + +/// Integer type for representing primary keys in database-related classes +typedef int TableKey; // changed in odemx-lite, was Int64 (platform dependend) + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_TABLEKEY_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/TypeInfo.h b/odemx-lite/include/odemx/data/TypeInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..8b510dfac1ac03d4c22743e75ccc040fa8f5814f --- /dev/null +++ b/odemx-lite/include/odemx/data/TypeInfo.h @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file data/TypeInfo.h + * @author Ronald Kluth + * @date created at 2009/09/05 + * @brief Declaration of type odemx::data::TypeInfo + * @since 3.0 + */ + +#ifndef ODEMX_DATA_TYPEINFO_INCLUDED +#define ODEMX_DATA_TYPEINFO_INCLUDED + +#include <CppLog/detail/TypeInfo.h> + +namespace odemx { +namespace data { + +/// Wrapper around std::type_info that can be used in containers +typedef Log::Detail::TypeInfo TypeInfo; + +} } // namespace odemx::data + +#endif /* ODEMX_DATA_TYPEINFO_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/buffer/SimRecordBuffer.h b/odemx-lite/include/odemx/data/buffer/SimRecordBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..e11d1c2788dcc429ce2b1c42346cf7773a0cbe21 --- /dev/null +++ b/odemx-lite/include/odemx/data/buffer/SimRecordBuffer.h @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimRecordBuffer.h + * @author Ronald Kluth + * @date created at 2009/09/14 + * @brief Declaration of class odemx::data::SimRecordBuffer + * @sa SimRecordBuffer.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_BUFFER_SIMRECORDBUFFER_INCLUDED +#define ODEMX_DATA_BUFFER_SIMRECORDBUFFER_INCLUDED + +#include <odemx/data/SimRecord.h> +#include <CppLog/ChannelId.h> +#include <CppLog/Record.h> +#include <deque> + +namespace odemx { +namespace data { + +// info types needed when buffering records +// used to prevent dangling pointers and provide additional info +CPPLOG_DECLARE_INFO_TYPE( ChannelInfo, "channel", std::string ); +CPPLOG_DECLARE_INFO_TYPE( ClassScopeInfo, "class_scope", std::string ); +CPPLOG_DECLARE_INFO_TYPE( SenderLabelInfo, "sender_label", Label ); +CPPLOG_DECLARE_INFO_TYPE( SenderTypeInfo, "sender_type", std::string ); +CPPLOG_DECLARE_INFO_TYPE( StringTimeInfo, "sim_time", std::string ); +CPPLOG_DECLARE_INFO_TYPE( SimIdInfo, "sim_id", TableKey ); + +namespace buffer { + +/** + * @brief Buffer for storing SimRecord information to allow deferred handling + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::SimRecord odemx::data::output::DatabaseWriter + * + * As soon as a log consumer needs to buffer data, as is the case with class + * odemx::data::output::DatabaseWriter, volatile information must be copied + * in order to be stored. Otherwise, there is a possibility for dangling + * pointers involved because SimRecords do not copy data for efficiency. + * Therefore, ODEMx offers this class in order to support the buffering of + * log records. + */ +class SimRecordBuffer +{ +public: + /// Record type used by the buffer for storing arbitrary information + struct StoredRecord: public Log::Record + { + /// Construction with record text, and details + StoredRecord( const Log::StringLiteral& text, std::shared_ptr< SimRecord::DetailVec > details ) + : text_( text ) + , details_( details ) + {} + + /// Access the string literal holding the record's text message + const Log::StringLiteral& getText() const + { + return text_; + } + + /// Check whether the record has details + bool hasDetails() const + { + return !! details_; + } + + /** + * @brief Get read access the detail vector + * @note This call will crash if the detail vector pointer is invalid. + * Always check @c hasDetails first. + */ + const SimRecord::DetailVec& getDetails() const + { + return *details_; + } + private: + /// A copy of the string literal that was sent as record text + Log::StringLiteral text_; + /// A copy of the shared_ptr to the detail vector created by SimRecord + std::shared_ptr< SimRecord::DetailVec > details_; + }; + + /// Vector type for storing simulation records + typedef std::deque< StoredRecord > StorageType; + /// Size type used for this buffer + typedef StorageType::size_type SizeType; + + /** + * @brief Construction + * @param limit Maximum number of records to be stored by the buffer + * + * @note The limit provides a means to check whether the buffer is full. + * However, it does not stop users from putting more data into the + * buffer, if necessary. + */ + SimRecordBuffer( SizeType limit ); + + /** + * @brief Add another record to the buffer + * @param channelId The channel over which the record was sent + * @param simRecord The actual record to extract the data from + * @param simId An ID representing the simulaiton context of the record + * @param timeString A string representation of the current SimTime + * + * This method copies all relevant information from the SimRecord + * and keeps it in a StoredRecord object. + */ + void put( const Log::ChannelId channelId, const SimRecord& simRecord, + const TableKey simId, const std::string& timeString ); + + /// Empty the buffer and reset size + void clear(); + + /// Check whether the buffer contains any records + bool isEmpty() const; + + /// Check whether the buffer has reached its limit + bool isFull() const; + + /// Get the current size of the buffer + SizeType getSize() const; + + /// Get the maximum size of the buffer + SizeType getLimit() const; + + /// Get a reference to the buffer's record vector + const StorageType& getStorage() const; + +private: + StorageType storage_; ///< Container for storing log records + SizeType size_; ///< Size counter to avoid use of size() method + SizeType limit_; ///< Maximum number of records the buffer can hold + + SimRecordBuffer( const SimRecordBuffer& ); ///< Non-copyable + SimRecordBuffer& operator=( const SimRecordBuffer& ); ///< Non-assignable +}; + +} } } // namespace odemx::data::buffer + +#endif /* ODEMX_DATA_BUFFER_SIMRECORDBUFFER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/buffer/StatisticsBuffer.h b/odemx-lite/include/odemx/data/buffer/StatisticsBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..f25beacaec016f6ecdb062da0f3ce0998eed2ddd --- /dev/null +++ b/odemx-lite/include/odemx/data/buffer/StatisticsBuffer.h @@ -0,0 +1,187 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file StatisticsBuffer.h + * @author Ronald Kluth + * @date created at 2009/04/07 + * @brief Declaration of class odemx::data::buffer::StatisticsBuffer + * @sa StatisticsBuffer.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_BUFFER_STATISTICSBUFFER_INCLUDED +#define ODEMX_DATA_BUFFER_STATISTICSBUFFER_INCLUDED + +#include <odemx/data/SimRecord.h> +#include <odemx/data/ReportProducer.h> +#include <odemx/statistics/Accumulate.h> + +#include <CppLog/Consumer.h> + +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +#include <deque> +#include <map> +#include <string> +#include <utility> + +//----------------------------------------------------------forward declarations + +namespace odemx { + +namespace base { class Simulation; } + +namespace data { +namespace buffer { + +//-----------------------------------------------------------header declarations + +/** + * @brief A log consumer class that computes and buffers simulation statistics + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::Producer odemx::data::LoggingManager + * + * In previous ODEMx versions, each @c ReportProducer stored its own + * accumulated statistical data. With database connectivity, ODEMx needed + * a concept that would allow the logging of each statistically relevant + * piece of data. Hence, ODEMx offers the log channel statistics and several + * convenience methods to create statistical log records. However, retaining + * the previous functionality where accumulated data can be computed without + * accessing a database, now requires a special log consumer class. + * + * The StatisticsBuffer consumes log records sent via channel @c statistics. + * Producers create such log records in a specific format (namely counters, + * parameters, updates, or resets) so that this consumer class can compute + * accumulated data from them. The buffer can also store all updates in memory + * so that it can be used later in the simulation programm. One such use is the + * computation of a histogram, for example. + * + * Besices the log consumer interface, this class also implements the report + * producer interface, meaning that it can directly be registered with a + * Report object in order to produce table-based statistics reports. This + * capability is also used when default logging is active. + */ +class StatisticsBuffer +: public Log::Consumer< SimRecord > +, public ReportProducer +{ +public: + + /// Deque type for storing property updates, i.e. pairs of SimTime and values + typedef std::deque< std::pair< base::SimTime, double > > UpdateDeque; + + /// Structure that holds value updates and the accumulated data + struct UpdateStats + { + UpdateStats( base::Simulation& sim, const data::Label& accumLabel ) + : accumulate( sim, accumLabel ) {} + statistics::Accumulate accumulate; + UpdateDeque updates; + }; + + /// Map type to associate parameter names and values + typedef std::map< StringLiteral, DynamicVar > ParamMap; + /// Map type to associate counted properties with counter values + typedef std::map< StringLiteral, std::size_t > CountMap; + /// Map type to associate updated properties with their statistical data + typedef std::map< StringLiteral, UpdateStats > UpdateMap; + + /** + * @brief Stores all statistical data of one statistics producer + * + * A @c Producer logs parameters, counters, and property updates, + * all of which can be stored by an object of this class. A + * @c ProducerStats object will be created for each statistics-producing + * object in a simulation. + */ + struct ProducerStats + { + base::SimTime resetTime; ///< last reset time + data::TypeInfo senderType; ///< sender type + ParamMap paramStats; ///< parameters + CountMap countStats; ///< counters + UpdateMap updateStats; ///< updates + }; + + /// Pointer type to manage @c ProducerStats + typedef std::shared_ptr< ProducerStats > ProducerStatsPtr; + + /// Buffer type for statistical data of many statistics producers + typedef std::map< Label, ProducerStatsPtr > StatisticsMap; + + /// Creation via static method to enforce shared_ptr use + static std::shared_ptr< StatisticsBuffer > create( + base::Simulation& sim, const Label& label, bool bufferUpdates = false ); + + /// Destruction + virtual ~StatisticsBuffer(); + + /// Check if the buffer contains any data + bool isEmpty() const; + + /// Get read access to the internal statistics storage + const StatisticsMap& getStatistics() const; + + /// Check whether update values are stored in a buffer + bool isBufferingUpdates() const; + + /// Get read access to the stored values of a producer's statistics property + const UpdateDeque& getUpdates( const Label& producer, + const StringLiteral& property ) const; + + /// Reset accumulated data (counters, updates) of all statistics producers + void reset( base::SimTime resetTime ); + +private: + /// Stores all statistics computed from simulation components + StatisticsMap statistics_; + /// Determines whether update values are buffered or not + bool bufferUpdates_; + +private: + /// Construction private, use create instead + StatisticsBuffer( base::Simulation& sim, const Label& label, bool bufferUpdates ); + + /// Implementation of ReportProducer interface + virtual void report( data::Report& report ); + + /// Implementation of log consumer interface, ignores all channels except @c statistics + virtual void consume( const Log::ChannelId channelId, const SimRecord& record ); + + /// Check for existing ProducerStats or create and add a new stats object + ProducerStatsPtr getObjectStats( const data::Producer& sender ); + + /// Non-copyable + StatisticsBuffer( const StatisticsBuffer& ); + /// Non-assignable + StatisticsBuffer& operator=( const StatisticsBuffer& ); +}; + +/// Smart pointer type to manage StatisticsBuffer objects +typedef std::shared_ptr< StatisticsBuffer > StatisticsBufferPtr; + +} } } // namespace odemx::data::buffer + +#endif /* ODEMX_DATA_BUFFER_STATISTICSBUFFER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/DefaultLoggingType.h b/odemx-lite/include/odemx/data/output/DefaultLoggingType.h new file mode 100644 index 0000000000000000000000000000000000000000..aa6d44e540686013b9f1dde13d8f0377584086f0 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/DefaultLoggingType.h @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file DefaultLoggingType.h + * @author Ronald Kluth + * @date created at 2010/04/12 + * @brief Declaration of enum odemx::data::output::Type + * @since 3.0 + */ + +#ifndef ODEMX_DATA_OUTPUT_DEFAULTLOGGINGTYPE_INCLUDED +#define ODEMX_DATA_OUTPUT_DEFAULTLOGGINGTYPE_INCLUDED + +namespace odemx { +namespace data { +namespace output { + +/** + * @brief Determines which output location should be used for default logging + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::LoggingManager + * + * ODEMx supports default logging output. This functionality can be activated + * by calling @c enableDefaultLogging on the Simulation object, which is a + * subclass of the LoggingManager. One required paramerter is the output type, + * i.e. one of the values of this enumeration. + */ +enum Type +{ + DATABASE = 100000,///< Enable database output, needs connection string + STDOUT, ///< Enable console output + XML ///< Enable XML file output, requires filename prefix +}; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_DEFAULTLOGGINGTYPE_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/DefaultTimeFormat.h b/odemx-lite/include/odemx/data/output/DefaultTimeFormat.h new file mode 100644 index 0000000000000000000000000000000000000000..07f0c374f111b0edd35a164bac78fd5f9d3f798c --- /dev/null +++ b/odemx-lite/include/odemx/data/output/DefaultTimeFormat.h @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file DefaultTimeFormat.h + * @author Ronald Kluth + * @date created at 2009/04/03 + * @brief Declaration of class odemx::data::output::DefaultTimeFormat + * @since 2.1 + */ + +#ifndef ODEMX_DATA_OUTPUT_DEFAULTTIMEFORMAT_INCLUDED +#define ODEMX_DATA_OUTPUT_DEFAULTTIMEFORMAT_INCLUDED + +#include <odemx/data/output/TimeFormat.h> +#include <odemx/util/StringConversion.h> + +namespace odemx { +namespace data { +namespace output { + +/** + * @brief Simple default implementation of a TimeFormat + * @ingroup data + * @author Ronald Kluth + * @since 2.1 + * @see odemx::data::output::TimeFormat odemx::data::output::GermanTime odemx::data::output::Iso8601Time + * + * The default time formatter is provided for log consumers that convert + * their SimTime values to strings. It can be used like any other TimeFormat, + * thus making them exchangeable for log consumers. All ODEMx log consumers + * have the capability to format SimTime. + */ +class DefaultTimeFormat +: public TimeFormat +{ +public: + /// Redefines computation function to avoid overhead, simply stores @c t in a member + virtual void computeTimeValues( base::SimTime t ); + /// Converts normal SimTime number to string without computing time units + virtual const std::string makeString() const; +}; + +//-----------------------------------------------------------------------inlines + +inline void DefaultTimeFormat::computeTimeValues( base::SimTime t ) +{ + simTime = t; +} + +inline const std::string DefaultTimeFormat::makeString() const +{ + return toString( simTime ); +} + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_DEFAULTTIMEFORMAT_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/ErrorWriter.h b/odemx-lite/include/odemx/data/output/ErrorWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..440619a712de1d94ff4086fe4537208d352c2f92 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/ErrorWriter.h @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ErrorWriter.h + * @author Ronald Kluth + * @date created at 2009/09/30 + * @brief Declaration of class odemx::data::output::ErrorWriter + * @sa ErrorWriter.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_OUTPUT_ERRORWRITER_INCLUDED +#define ODEMX_DATA_OUTPUT_ERRORWRITER_INCLUDED + +#include <odemx/data/SimRecord.h> +#include <CppLog/Consumer.h> + +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace data { +namespace output { + +class TimeFormat; + +//-----------------------------------------------------------header declarations + +/** + * @brief A log consumer specifically intended for warnings, errors, and fatal errors + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::Producer + * + * This class outputs error messages in a similar way as previous ODEMx + * versions. However, with the use of class SimRecord as record type, + * much more detailed information can be given about the error condition. + * + * @note This consumer type is meant to be registered only with the + * channels warning, error, and fatal. Otherwise, an error message will + * be generated. + */ +class ErrorWriter +: public Log::Consumer< SimRecord > +{ +public: + /** + * @brief Creation by static method + * @return A shared pointer that manages the consumer object. + * + * This method forces the use of reference-counting pointers to data + * consumer objects in order to avoid manual memory management of these + * resources. ODEMx log channels maintain a set of shared pointers to + * their consumers, which guarantees that consumer objects stay alive while + * they are registered with a channel. + */ + static std::shared_ptr< ErrorWriter > create(); + + /// Destruction + virtual ~ErrorWriter(); + + /** + * @brief Implementation of the consumer interface, writes records to std::cerr + * @param channelId ID of the forwarding log channel + * @param record A log record describing the detected failure + * + * The output format contains the type of failure (i.e. the channel), + * the message, the SimTime, the sender and its type. Details and class + * scope are optional data. + */ + virtual void consume( const Log::ChannelId channelId, const SimRecord& record ); + + /** + * @brief Set a new time formatter + * @param timeFormat Pointer to a dynamically allocated time formatter + * @see odemx::data::output::GermanTime odemx::data::output::Iso8601Time + * + * The default formatter simply outputs SimTime values, i.e. numbers. + * With this method, the format can be changed. The function takes + * ownership of the pointer and deletes it automatically when the writer is + * destroyed or the format is changed. + */ + void setTimeFormat( TimeFormat* timeFormat ); + +private: + /// Pointer to the time formatter, if set + std::unique_ptr< TimeFormat > format_; + +private: + /// Construction private, use create instead + ErrorWriter(); + /// Non-copyable + ErrorWriter( const ErrorWriter& ); + /// Non-assignable + ErrorWriter& operator=( const ErrorWriter& ); +}; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_ERRORWRITER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/GermanTime.h b/odemx-lite/include/odemx/data/output/GermanTime.h new file mode 100644 index 0000000000000000000000000000000000000000..0ce48015325497dfb95e3881c31a87b5d9340d36 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/GermanTime.h @@ -0,0 +1,86 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file GermanTime.h + * @author Ronald Kluth + * @date created at 2009/04/03 + * @brief Declaration of class odemx::data::output::GermanTime + * @sa GermanTime.cpp + * @since 2.1 + */ + +#ifndef ODEMX_DATA_OUTPUT_GERMANTIME_INCLUDED +#define ODEMX_DATA_OUTPUT_GERMANTIME_INCLUDED + +#include <odemx/data/output/TimeFormat.h> + +#include <string> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace data { +namespace output { + +struct TimeBase; + +//-----------------------------------------------------------header declarations + +/** + * @brief Implementation of the German time format + * @ingroup data + * @author Ronald Kluth + * @since 2.1 + * @see odemx::data::output::TimeFormat odemx::data::output::Iso8601Time + * + * This time formatter converts SimTime to the German time format + * <tt>YYYY-MM-DD / hh:mm:ss.f</tt>. It uses the predefined computation + * function from TimeFormat and merely provides a string conversion + * for the computed values. + * + * The default precision for the generated strings is seconds. + * The millisecond part will only be displayed if the given TimeBase + * uses the TimeUnit milliseconds. + */ +class GermanTime +: public TimeFormat +{ +public: + /// Default construction + GermanTime(); + /// Construction with given time base (SimTime 0 represents this time) + GermanTime( const TimeBase& base ); + +protected: + // uses predefined computation function from Format() + + /** + * @brief Transforms the computed values to the output format + * @return A formatted time string + * + * This method is called by TimeFormat::timeToString() after the + * values for date and day time have been computed. It merely + * transforms that data into an std::string. + */ + virtual const std::string makeString() const; +}; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_GERMANTIME_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/Iso8601Time.h b/odemx-lite/include/odemx/data/output/Iso8601Time.h new file mode 100644 index 0000000000000000000000000000000000000000..534e334a521087a6b097350533861461ddb24007 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/Iso8601Time.h @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Iso8601Time.h + * @author Ronald Kluth + * @date created at 2009/04/03 + * @brief Declaration of class odemx::data::output::Iso8601Time + * @sa Iso8601Time.cpp + * @since 2.1 + */ + +#ifndef ODEMX_DATA_OUTPUT_ISO8601TIME_INCLUDED +#define ODEMX_DATA_OUTPUT_ISO8601TIME_INCLUDED + +#include <odemx/data/output/TimeFormat.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace data { +namespace output { + +struct TimeBase; + +//-----------------------------------------------------------header declarations + +/** + * @brief Implementation of the ISO-8601 time format + * @ingroup data + * @author Ronald Kluth + * @since 2.1 + * @see odemx::data::output::TimeFormat odemx::data::output::Iso8601Time + * + * This time formatter converts SimTime to the ISO 8601 time format + * <tt>YYYY-MM-DDThh:mm:ss.f±HH:mm</tt>. It uses the predefined + * computation function from TimeFormat and merely provides a string + * conversion for the computed values. + * + * This implementation features a subset, as proposed by the W3C, of the + * whole ISO-8601 standard for outputting international dates and time. + * It enables output of different time precisions ranging from minutes over + * seconds up to milliseconds. + * + * The default precision for the generated strings is seconds. + * The millisecond part will only be displayed if the given TimeBase + * uses the unit milliseconds. + */ +class Iso8601Time +: public TimeFormat +{ +public: + /// Structure that describes the Offset ofa time zone from UTC time + struct UtcOffset + { + /// Construction + UtcOffset( short h, unsigned short m ); + + short hour; ///< time zone hour offset from UTC + unsigned short minute; ///< time zone minute offset from UTC + }; + + /** + * @brief Construction with TieBase + * @param base The point in time that represents SimTime 0 + * @param utcOffsetHour UTC offset hour part + * @param utcOffsetMin UTC offset minute part + * + * The UTC offset is limited to narrow ranges of values. + * The hour part ranges from -12 though 14, and the minute part may + * only contain the values 0, 15, 30, or 45. + */ + explicit Iso8601Time( const TimeBase& base, short utcOffsetHour = 0, + unsigned short utcOffsetMin = 0 ); + + // uses predefined computation function from Format() + + /// defines the output format of the time string + virtual const std::string makeString() const; + + /// Change to UTC time offset + void setUtcOffset( short hour, short minute ); + /// Get the offset from UTC time + const UtcOffset& getUtcOffset() const; + +private: + UtcOffset utcOffset_; ///< time zone to be added +}; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_ISO8601TIME_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/OStreamReport.h b/odemx-lite/include/odemx/data/output/OStreamReport.h new file mode 100644 index 0000000000000000000000000000000000000000..119c021fbc654dd4d4460820f86be2d967c0bc55 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/OStreamReport.h @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file OStreamReport.h + * @author Ronald Kluth + * @date created at 2009/02/28 + * @brief Declaration of class odemx::data::output::OStreamReport + * @sa OStreamReport.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_OUTPUT_OSTREAMREPORT_INCLUDED +#define ODEMX_DATA_OUTPUT_OSTREAMREPORT_INCLUDED + +#include <odemx/data/Report.h> +#include <ostream> + +namespace odemx { +namespace data { +namespace output { + +/** + * @brief Simple Report implementation that prints statistics tables to a stream + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::Report odemx::data::ReportProducer odemx::data::output::XmlReport + * + * ODEMx can collect statistical data in accumulated form. This is either + * done by statistics computing components provided by module statistics, + * or with the help of the log consumer odemx::data::buffer::StatisticsBuffer + * that collects data from channel statistics. + * + * This class is mainly used to print accumulated statistical data to the + * console by providing std::cout as target stream. However, it is also + * possible to use file streams or other subclasses of std::ostream. + */ +class OStreamReport +: public Report +{ +public: + /// Construction with @c ostream + OStreamReport( std::ostream& os ); + /// Destruction + virtual ~OStreamReport(); + +protected: + /// Redefined to output a headline before showing the tables + virtual void startProcessing(); + /// Prints formatted tables from ReportProducers to the stream + virtual void processTables(); + /// Does nothing + virtual void endProcessing(); + +private: + /// Reference to the @c ostream the report will be written to + std::ostream& os_; +}; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_OSTREAMREPORT_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/OStreamWriter.h b/odemx-lite/include/odemx/data/output/OStreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..5aaff13f33ab49bb8f2bc825550598b2f3f8d988 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/OStreamWriter.h @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file data/output/OStreamWriter.h + * @author Ronald Kluth + * @date created at 2009/02/09 + * @brief Declaration of class odemx::data::output::OStreamWriter + * @sa OStreamWriter.cpp + * @since 3.0 + */ + +#ifndef ODEMX_DATA_OUTPUT_OSTREAMWRITER_INCLUDED +#define ODEMX_DATA_OUTPUT_OSTREAMWRITER_INCLUDED + +#include <odemx/data/SimRecord.h> +#include <CppLog/Consumer.h> + +#include <ostream> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace data { +namespace output { + +class TimeFormat; + +//-----------------------------------------------------------header declarations + +/** + * @brief A simple log consumer implementation for writing plain text + * @ingroup data + * @author Ronald Kluth + * @since 3.0 + * @see odemx::data::Producer + * + * This data consumer accepts a reference to any \c std::ostream object and + * immediately writes records to it when \c consume() is called. The time + * format of the record output is changeable. + */ +class OStreamWriter +: public Log::Consumer< SimRecord > +{ +public: + /** + * @brief Creation by static method + * @param os The \c std::ostream to which output will be written + * @return A shared_ptr-managed OStreamWriter object + * + * This method enforces the use of reference-counting pointers to data + * consumer objects in order to avoid manual memory management of these + * resources. ODEMx log channels maintain a set of shared pointers to + * their consumers, which guarantees that consumer objects stay alive while + * they are registered with a channel. + */ + static std::shared_ptr< OStreamWriter > create( std::ostream& os ); + + /// Destruction + virtual ~OStreamWriter(); + + /** + * @brief Implementation of the consumer interface, writes records to a stream + * @param channelId ID of the forwarding log channel + * @param record A log record describing the current simulation event + * + * Each record is printed on a single line. The output format contains + * the formatted simulation time, the channel name, the producer label, + * and the message text. Additionally, details and scope may be printed, + * if the record contains any. + */ + virtual void consume( const Log::ChannelId channelId, const SimRecord& record ); + + /** + * @brief Set a new time formatter + * @param timeFormat Pointer to a dynamically allocated time formatter + * @see odemx::data::output::GermanTime odemx::data::output::Iso8601Time + * + * The default formatter simply outputs SimTime values. The function takes + * ownership of the pointer and deletes it automatically when the writer is + * destroyed or the format is changed. + */ + void setTimeFormat( TimeFormat* timeFormat ); + +private: + /// Internal reference to the consuming ostream object. + std::ostream& os_; + /// Pointer to the time formatter, if set + std::unique_ptr< TimeFormat > format_; + + /// Construction only via create() + OStreamWriter( std::ostream& os ); + /// Non-copyable + OStreamWriter( const OStreamWriter& ); + /// Non-assignable + OStreamWriter& operator=( const OStreamWriter& ); +}; + +/// Smart pointer type to manage OStreamWriter objects +typedef std::shared_ptr< OStreamWriter > OStreamWriterPtr; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_OSTREAMWRITER_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/TimeBase.h b/odemx-lite/include/odemx/data/output/TimeBase.h new file mode 100644 index 0000000000000000000000000000000000000000..6dff1cc0577de0e6463817f4a6e14c5931732ae0 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/TimeBase.h @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TimeBase.h + * @author Ronald Kluth + * @date created at 2009/04/03 + * @brief Declaration of class odemx::data::output::TimeBase + * @sa TimeBase.cpp + * @since 2.1 + */ + +#ifndef ODEMX_DATA_OUTPUT_TIMEBASE_INCLUDED +#define ODEMX_DATA_OUTPUT_TIMEBASE_INCLUDED + +#include <odemx/data/output/TimeUnit.h> + +namespace odemx { +namespace data { +namespace output { + +/** + * @brief Describes the time base in day, month, year, day time offset and unit + * @ingroup data + * @author Ronald Kluth + * @since 2.1 + * @see odemx::data::output::GermanTime odemx::data::output::Iso8601Time + * + * SimTime is an abstraction from real time. It always starts at 0, and the + * user interprets which time units are used. In order to output formatted + * SimTime values, two pieces of information are required: the starting point + * in time, and the unit to be used. This class provides both. + */ +struct TimeBase +{ + /** + * @brief Construction, initializes all members at once + * @param year The year of the start date + * @param month The month of the start date + * @param day The day of the start date + * @param dayTimeOffset The daytime offset on the start date in units + * @param unit The unit to be used when converting SimTime + * + * + */ + TimeBase( unsigned short year, unsigned short month, unsigned short day, + base::SimTime dayTimeOffset, TimeUnit::Type unit ); + + unsigned short year; ///< time base year + unsigned short month; ///< time base month + unsigned short day; ///< time base day + base::SimTime offset; ///< time offset on the given day, must respect unit + TimeUnit::Type unit; ///< time base unit +}; + +//-----------------------------------------------------------------------inlines + +inline TimeBase::TimeBase( unsigned short year, unsigned short month, + unsigned short day, base::SimTime dayTimeOffset, TimeUnit::Type unit ) +: year( year ) +, month( month ) +, day( day ) +, offset( dayTimeOffset ) +, unit( unit ) +{ +} + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_TIMEBASE_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/TimeFormat.h b/odemx-lite/include/odemx/data/output/TimeFormat.h new file mode 100644 index 0000000000000000000000000000000000000000..490b39f7dd9218c19b8b1168c7b186e0ae481ce7 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/TimeFormat.h @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TimeFormat.h + * @author Ronald Kluth + * @date created at 2008/03/14 + * @brief Declaration of odemx::data::output::TimeFormat + * @sa TimeFormat.cpp + * @since 2.1 + */ + +#ifndef ODEMX_DATA_OUTPUT_TIMEFORMAT_INCLUDED +#define ODEMX_DATA_OUTPUT_TIMEFORMAT_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/data/output/TimeBase.h> +#include <odemx/data/output/TimeUnit.h> + +#include <string> + +namespace odemx { +namespace data { +namespace output { + +/** + * @brief Abstract base class for formatted simulation time output + * @ingroup data + * @author Ronald Kluth + * @since 2.1 + * @see odemx::data::output::GermanTime odemx::data::output::Iso8601Time + * + * This abstract base class provides an implementation for time computations. + * In order to transform an abstract SimTime value into a concrete time + * value, a starting point and a time unit are required. Both are provided + * in the form of a TimeBase object. + * + * This class computes year, month, day, hour minutes, and seconds from SimTime + * values and stores them in protected members so that they can be used by + * subclasses to produce a formatted time string. The interface for converting + * SimTime to string is provided by the member function @c timeToString. + */ +class TimeFormat +{ +public: + /// Default construction for uninitialized TimeFormat objects + TimeFormat(); + /// Construction with a given time base and unit + TimeFormat( const TimeBase& timeBase ); + /// Destruction + virtual ~TimeFormat(); + + /// Set the time base (date, time of day, unit) for the time computation + void setTimeBase( unsigned short year, unsigned short month, + unsigned short day, base::SimTime dayTimeOffset, TimeUnit::Type unit ); + /// Set the time base by providing a TimeBase object + void setTimeBase( const TimeBase& timeBase ); + /// Get a reference to the format's time base + const TimeBase& getTimeBase() const; + + /** + * @brief Transforms SimTime into a formatted string for logging output + * @param time The SimTime value to be transformed + * @return A string representation of the given SimTime value + * + * This function can be used by all output components to transform + * SimTime values into actual dates and points in time. To achieve this, + * the function uses the virtual function @c computeTimeValues to + * determine the date and time according to the time base and unit. + * + * Finally, this function calls the pure virtual function makeString(), + * which must be defined by all subclasses in order to produce the + * formatted string from the internal numeric time representation. + */ + const std::string timeToString( base::SimTime time ); + +protected: + + /// Computes a real date and clock time from SimTime, stores values in member data + virtual void computeTimeValues( base::SimTime time ); + + /** + * @brief Assembles the previously computed values as formatted time string + * + * All subclasses must provide an implementation of this function so that + * @c timeToString can be called for the time transformation. + */ + virtual const std::string makeString() const = 0; + + /// The starting point of the simulation time, represents SimTime 0 + TimeBase base; + + // values to be set by computeTimeValues() + base::SimTime simTime; ///< The SimTime to be converted considering base + unsigned short year; ///< Computed year + unsigned short month; ///< Computed month + unsigned short day; ///< Computed day + unsigned short hour; ///< Computed hour + unsigned short min; ///< Computed minutes + double sec; ///< Computed seconds and milliseconds + + /// Heper function to get the days of a month, with regard to the year + static unsigned short daysOfMonth( unsigned short month, unsigned short year ); +private: + /// Reset member data, used for initialization and reset + void resetTimeValues(); +}; + +} } } // namespace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_TIMEFORMAT_INCLUDED */ diff --git a/odemx-lite/include/odemx/data/output/TimeUnit.h b/odemx-lite/include/odemx/data/output/TimeUnit.h new file mode 100644 index 0000000000000000000000000000000000000000..c0da935e0c80f15d38f3b1e0f609e12856139a76 --- /dev/null +++ b/odemx-lite/include/odemx/data/output/TimeUnit.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TimeUnit.h + * @author Ronald Kluth + * @date created at 2008/03/14 + * @brief Declaration of odemx::data::output::TimeUnit + * @sa TimeUnit.cpp + * @since 2.1 + */ + +#ifndef ODEMX_DATA_OUTPUT_TIMEUNIT_INCLUDED +#define ODEMX_DATA_OUTPUT_TIMEUNIT_INCLUDED + +namespace odemx { +namespace data { +namespace output { + +/** + * @brief SimTime always represents one of these time units + * @ingroup data + * @author Ronald Kluth + * @since 2.1 + * @see odemx::data::output::TimeBase odemx::data::output::TimeFormat + * + * The computation of real dates from SimTime requires a starting point, + * and a time unit. The latter are represented by values of this enumeration. + */ +struct TimeUnit +{ + enum Type + { + none, + milliseconds, + seconds, + minutes, + hours + }; +}; + +} } } // namspace odemx::data::output + +#endif /* ODEMX_DATA_OUTPUT_TIMEUNIT_INCLUDED */ diff --git a/odemx-lite/include/odemx/odemx.h b/odemx-lite/include/odemx/odemx.h new file mode 100644 index 0000000000000000000000000000000000000000..a887bff8f72b658f8257d20a5a51cc2e4952ddd2 --- /dev/null +++ b/odemx-lite/include/odemx/odemx.h @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file odemx.h + * @author Ralf Gerstenberger + * @date created at 2002/08/05 + * @brief Includes all ODEMx header files + * @since 1.0 + */ + +#ifndef ODEMX_ODEMX_INCLUDED +#define ODEMX_ODEMX_INCLUDED + +// base package +#include <odemx/base/Comparators.h> +#include <odemx/base/Continuous.h> +#include <odemx/base/DefaultSimulation.h> +#include <odemx/base/Event.h> +#include <odemx/base/ExecutionList.h> +#include <odemx/base/Process.h> +#include <odemx/base/Sched.h> +#include <odemx/base/Scheduler.h> +#include <odemx/base/SimTime.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/TypeDefs.h> + +// control package +#include <odemx/base/control/ControlBase.h> +#include <odemx/base/control/Control.h> + +// continuous package +// removed in odemx-lite + +// cellular automaton package +#include <odemx/base/cellular_automaton/CellMonitor.h> +#include <odemx/base/cellular_automaton/Cell.h> +#include <odemx/base/cellular_automaton/CellVariablesContainer.h> + +// coroutine package +#include <odemx/coroutine/Coroutine.h> +#include <odemx/coroutine/CoroutineContext.h> +#include <odemx/coroutine/System.h> + +// data package +#include <odemx/data/LoggingManager.h> +#include <odemx/data/Label.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/Observable.h> +#include <odemx/data/Producer.h> +#include <odemx/data/SimRecord.h> +#include <odemx/data/SimRecordFilter.h> +#include <odemx/data/TableKey.h> +#include <odemx/data/TypeInfo.h> + +// buffer sub-package +#include <odemx/data/buffer/SimRecordBuffer.h> +#include <odemx/data/buffer/StatisticsBuffer.h> + +// output sub-package +// removed in odemx-lite +// #include <odemx/data/output/DatabaseWriter.h> +#include <odemx/data/output/DefaultLoggingType.h> +#include <odemx/data/output/DefaultTimeFormat.h> +#include <odemx/data/output/ErrorWriter.h> +#include <odemx/data/output/GermanTime.h> +#include <odemx/data/output/Iso8601Time.h> +#include <odemx/data/output/OStreamReport.h> +#include <odemx/data/output/OStreamWriter.h> +#include <odemx/data/output/TimeBase.h> +#include <odemx/data/output/TimeFormat.h> +#include <odemx/data/output/TimeUnit.h> +// removed in odemx-lite +// #include <odemx/data/output/XmlReport.h> +// #include <odemx/data/output/XmlWriter.h> + +// protocol package +#include <odemx/protocol/Device.h> +#include <odemx/protocol/Entity.h> +#include <odemx/protocol/ErrorModel.h> +#include <odemx/protocol/Layer.h> +#include <odemx/protocol/Medium.h> +#include <odemx/protocol/Pdu.h> +#include <odemx/protocol/Sap.h> +#include <odemx/protocol/Service.h> +#include <odemx/protocol/ServiceProvider.h> +#include <odemx/protocol/Stack.h> + +// random package +#include <odemx/random/ContinuousConst.h> +#include <odemx/random/ContinuousDist.h> +#include <odemx/random/DiscreteConst.h> +#include <odemx/random/DiscreteDist.h> +#include <odemx/random/Dist.h> +#include <odemx/random/DistContext.h> +#include <odemx/random/Draw.h> +#include <odemx/random/Erlang.h> +#include <odemx/random/NegativeExponential.h> +#include <odemx/random/Normal.h> +#include <odemx/random/Poisson.h> +#include <odemx/random/RandomInt.h> +#include <odemx/random/Uniform.h> + +// statistics package +#include <odemx/statistics/Accumulate.h> +#include <odemx/statistics/Count.h> +#include <odemx/statistics/Histogram.h> +#include <odemx/statistics/Regression.h> +#include <odemx/statistics/Sum.h> +#include <odemx/statistics/Tab.h> +#include <odemx/statistics/Tally.h> + +// synchronization package +#include <odemx/synchronization/Bin.h> +#include <odemx/synchronization/BinT.h> +#include <odemx/synchronization/CondQ.h> +#include <odemx/synchronization/IMemory.h> +#include <odemx/synchronization/Memory.h> +#include <odemx/synchronization/Port.h> +#include <odemx/synchronization/ProcessQueue.h> +#include <odemx/synchronization/Queue.h> +#include <odemx/synchronization/Res.h> +#include <odemx/synchronization/ResT.h> +#include <odemx/synchronization/Timer.h> +#include <odemx/synchronization/Wait.h> +#include <odemx/synchronization/WaitQ.h> + +// util package +#include <odemx/util/DeletePtr.h> +#include <odemx/util/Exceptions.h> +#include <odemx/util/ListInSort.h> +#include <odemx/util/StringConversion.h> +#include <odemx/util/TypeNames.h> +#include <odemx/util/TypeToString.h> +#include <odemx/util/Version.h> + +// simml package +// removed in odemx-lite + +#endif diff --git a/odemx-lite/include/odemx/protocol/Device.h b/odemx-lite/include/odemx/protocol/Device.h new file mode 100644 index 0000000000000000000000000000000000000000..b335485102a42291968e0f184ef22d210a297411 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Device.h @@ -0,0 +1,281 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Device.h + * @author Ronald Kluth + * @date created at 2009/10/31 + * @brief Declaration of class odemx::protocol::Device + * @sa Device.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_DEVICE_INCLUDED +#define ODEMX_PROTOCOL_DEVICE_INCLUDED + +#include <odemx/protocol/ServiceProvider.h> +#include <odemx/synchronization/Memory.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace protocol { + +class Medium; + +//-----------------------------------------------------------header declarations + +/** + * @brief Base class for modeling network interfaces + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Medium odemx::protocol::Stack + * + * A Device object models a network interface in ODEMx protocol stacks. As such + * it is a means by which nodes in a network can communicated with each other. + * Using a device always requires the use of a transmission medium because + * that is needed to transport data from one node to another. Hence, this class + * and the class Medium are closely tied. + * + * In order to build a network topology, all devices that are connected + * to a specific medium must explicitly be registered with it by their address. + * Links between nodes are formed as links between devices. For this purpose, + * their addresses are used. Transmissions from device always pass through the + * medium. Whenever a device sends data, the medium schedules transmission + * events to notify the neighbors of a node about the start, and the end of each + * transmission. + * + * Using two events for transmissions allows to integrate a collision detection + * mechanism. Collisions occur when two connected devices start sending at + * roughly the same so that they have not yet received the start events of their + * neighbor. + */ +class Device +: public ServiceProvider +{ +private: + /// Memory type that allows the stopping of a transmission when a collision occurs + typedef synchronization::Memory CollisionDetection; + +public: + /// Address type to be used by device ojects + typedef std::string AddressType; + + /** + * @brief Construction + * @param sim The simulation context + * @param label The label of the object + * + * The constructor initializes an internal SAP that is needed for + * receiving data from the medium. Since devices are service providers, + * they also just listen for input and wait. They must therefore be + * awakened by an internal SAP when data is transmitted via + * the medium + */ + Device( base::Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~Device(); + + /** + * @brief Set the address of a device + * + * Normally, there is no need to use this method manually. Upon registration + * with a Medium, the device will automatically receive the address provided + * in the call to @c registerDevice. + */ + void setAddress( const AddressType& addr ); + + /// Read the device address. It may not have been set yet. + const AddressType& getAddress() const; + + /// Set the medium that connects the device to its peers + void setMedium( Medium& medium ); + + /// Reset the internal medium pointer + void resetMedium(); + + /// Check if the medium is set + bool hasMedium() const; + + /** + * @brief Increase the number of active transmissions at the device + * @see decTransmissionCount, busy + * + * This function is called when the device itself begins to transmit, or + * when it is notified by one of its neighbors about a transmission start. + * Keeping track of the active transmissions is important for implementing + * the collision detection mechanism. A collision occurrs when a device's + * active transmission count is greater than one. Depending on the + * implementation of @c hasCollisionDetection, the device may abort + * its own transmission, or it must wait until all of its data is sent. + * The latter functionality is implemented with a duration timer. + */ + void incTransmissionCount(); + + /** + * @brief Decrease the number of active transmissions + * @see incTransmissionCount, busy + * + * Whenever the device or its neighbors finish a transmission, this + * function is called to decrease the transmission counter. + */ + void decTransmissionCount(); + + /// Check the number of active transmissions at the device + unsigned int getTransmissionCount() const; + +protected: + + /** + * @name Input handling, to be defined by subclasses + * @{ + */ + /** + * @brief Implements the device functionality for sending data + * @param sapName The SAP used to input the data + * @param p The data unit to be transmitted via medium + * + * Whenever data is provided by an SAP other than the internal receive + * SAP, this pure virtual method is called with the name of the SAP + * and the PDU to send. Every device must implement this method in + * order to specify how an what data is to be transmitted via the medium. + * Usually, this method calls @c send. + */ + virtual void handleSend( const std::string& sapName, PduPtr p ) = 0; + /** + * @brief Implement the device functionality for message reception + * @param p The data unit received from the medium + * + * This method gets called whenever data arrives from the medium through + * the internal receive SAP. The device must implement this method to + * define if and how data is to be passed to the upper layer or not. + * Usually, this method calls @c pass. + */ + virtual void handleReceive( PduPtr p ) = 0; + //@} + + /** + * @brief Transmit data via the associated medium + * @param p The protocol data unit to be transmitted + * @see computeTransmissionDuration + * + * Sending data is a complex operation since it involves the interaction + * with the transmission medium. First, the medium is checked if it's busy. + * In that case, the method returns @c false immediately. + * + * Otherwise, a transmission is started by increasing the counter and + * calling @c signalTransmissionStart on the Medium object. This schedules + * TransmissionStart events for all neighbors. Afterwards, the transmission + * duration is calculated dependant on the PDU size by calling + * @c computeTransmissionDuration. + * + * Depending on whether @c hasCollisionDetection returns @c true or + * @c false, an active transmission may be stopped upon collision + * detection or not. In the case of a collision, an empty PDU will + * be delivered to the receivers. + * + * As soon as the wait period ends, the end of the transmission is + * made know to all neighbors by calling @c signalTransmissionEnd on the + * Medium object. This schedules TransmissionEnd events, which decrease + * the counter at the receiver and deliver the PDU. + */ + bool send( PduPtr p ); + + /** + * @brief Pass a message from the medium to the upper layer + * @param upperLayerSap The SAP to which to pass the data unit + * @param p The data unit to pass on + * + * This method simply looks up the SAP in the upper layer and writes + * the given data unit to it. A warning will be issued if the SAP + * is not found. + */ + void pass( const std::string& upperLayerSap, PduPtr p ); + + /** + * @brief Override of the service provider interface + * @param sap The SAP by which the data unit was provided + * @param p The protocol data unit to handle + * + * This function simply calls @c handleReceive if the PDU came from the + * internal SAP. Otherwise, @c handleReceive is called. + */ + virtual void handleInput( const std::string& sap, PduPtr p ); + + /** + * @brief Determine the time it takes to transmit a data unit via medium + * @param pduSize The size of the given data unit + * @return The time duration it will take to put the PDU on the medium + * + * This method is important for the waiting period between transmission + * start and end. It computes the time it takes the device to put a + * given data unit on the medium. Device subclasses must define this + * method in order to provide a sensible implementation depending on + * bandwidth and Ouality of service. + */ + virtual base::SimTime computeTransmissionDuration( std::size_t pduSize ) = 0; + + /** + * @brief Determines whether a device can detect collision + * @return @c true if the device has collision detection capability, @c false otherwise + * + * Normally, a device has to send all of its data to the medium, not knowing + * whether it actually arrives intact. However, some devices can abort their + * transmission when a collision is detected on the medium. This method's + * implementation decides whether the device has this ability or not. + */ + virtual bool hasCollisionDetection(); + +public: + /** + * @brief Put a data unit into the device's receive SAP + * + * This method should not be called manually. It is part of the interaction + * between Medium and Device, and it is always called by TransmissionEnd + * events to deliver a PDU from the medium. + */ + void receive( PduPtr p ); + +private: + /// SAP that receives PDUs from the medium + Sap* receiveSap_; + /// Address of the device + AddressType address_; + /// Medium used by the device to transmit messages + Medium* medium_; + /// Counts the number of active transmissions on the device to detect collisions + unsigned int transmissionCount_; + /// Memory object that can awaken the device early from its transmission wait period + CollisionDetection collisionDetection_; + /// Stores whether a collision occurred during the last transmission + bool collisionOccurred_; + +protected: + /// Check if the device finds the medium busy + bool busy() const; + /// Schedule events for all neighbors to notify them of a transmission start + void startTransmission(); + /// Schedule events for all neighbors to notify them of a transmission end and deliver the PDU + void endTransmission( PduPtr p ); +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_DEVICE_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Entity.h b/odemx-lite/include/odemx/protocol/Entity.h new file mode 100644 index 0000000000000000000000000000000000000000..d4f793b8cfe5d2a6a8b91d5963b6fd6799a1b2aa --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Entity.h @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Entity.h + * @author Ronald Kluth + * @date created at 2009/10/13 + * @brief Declaration of class odemx::protocol::Entity + * @sa Entity.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_ENTITY_INCLUDED +#define ODEMX_PROTOCOL_ENTITY_INCLUDED + +#include <odemx/protocol/ServiceProvider.h> +#include <odemx/protocol/Sap.h> + +namespace odemx { +namespace protocol { + +/** + * @brief Base class for modeling all kinds of protocol entities + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Device odemx::protocol::Service + * + * An Entity extends the service provider functionality by the methods + * @c send and @c pass, which are used for forwarding protocol data units + * between adjacent layers of the protocol stack. + */ +class Entity +: public ServiceProvider +{ +public: + + /// Construction + Entity( base::Simulation& sim, const data::Label& label ); + /// Destruction + virtual ~Entity(); + + /** + * @brief Forward a PDU to the lower layer via the given SAP + * @param lowerLayerSap The target SAP in the lower layer + * @param p The protocol data unit to be forwarded + * + * The function simply requests the given SAP from the lower layer + * and writes the PDU to it. + */ + void send( const std::string& lowerLayerSap, PduPtr p ); + + /** + * @brief Forward a PDU to the upper layer via the given SAP + * @param upperLayerSap The target SAP in the upper layer + * @param p The protocol data unit to be forwarded + * + * The function simply requests the given SAP from the upper layer + * and writes the PDU to it. + */ + void pass( const std::string& upperLayerSap, PduPtr p ); + + /// Service provider interface, must be implemented in subclasses + virtual void handleInput( const std::string& sapName, PduPtr ) = 0; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_ENTITY_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/ErrorModel.h b/odemx-lite/include/odemx/protocol/ErrorModel.h new file mode 100644 index 0000000000000000000000000000000000000000..be114c23be1d91ab49085cf84b2727f6fa534faf --- /dev/null +++ b/odemx-lite/include/odemx/protocol/ErrorModel.h @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ErrorModel.h + * @author Ronald Kluth + * @date created at 2009/10/18 + * @brief Declaration of interface odemx::protocol::ErrorModel + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_ERRORMODEL_INCLUDED +#define ODEMX_PROTOCOL_ERRORMODEL_INCLUDED + +#include <odemx/protocol/Pdu.h> + +namespace odemx { +namespace protocol { + +/** + * @brief Interface for error models used by classes Medium and Service + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Medium odemx::protocol::Service + * + * When modeling network simulations, it is also necessary to be able to + * create different failure situations. In order to allow the definition of + * any kind of failure that can occur during data transmission, the interface + * ErrorModel is provided. + */ +class ErrorModel +{ +public: + /// Destruction + virtual ~ErrorModel() {} + + /** + * @brief Process a transmitted message + * @param The PDU to be evaluated by the error model + * @retval @c true if the PDU may pass (even if it was altered) + * @retval @c false if the PDU shall not arrive at its destination + * + * The method may either drop the data unit completely, or it may + * merely change its contents, for example to model bit errors. + */ + virtual bool apply( PduPtr p ) = 0; +}; + +/// Smart pointer type to manage the lifetime of error model objects +typedef std::shared_ptr< ErrorModel > ErrorModelPtr; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_ERRORMODEL_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/ErrorModelDraw.h b/odemx-lite/include/odemx/protocol/ErrorModelDraw.h new file mode 100644 index 0000000000000000000000000000000000000000..4d484b1028335e4745df2a9f79d7b221387306b2 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/ErrorModelDraw.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ErrorModelDraw.h + * @author Ronald Kluth + * @date created at 2010/04/05 + * @brief Declaration of class odemx::protocol::ErrorModelDraw + * @sa ErrorModelDraw.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_ERRORMODELDRAW_INCLUDED +#define ODEMX_PROTOCOL_ERRORMODELDRAW_INCLUDED + +#include <odemx/protocol/ErrorModel.h> +#include <odemx/random/Draw.h> + +namespace odemx { +namespace protocol { + +/** + * @brief Simle ErrorModel implementation + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::ErrorModel odemx::random::Draw + * + * This class provides a random-number-based approach to model transmission + * failures. It uses an odemx::random::Draw object in order to simulate + * the loss of PDUs during transmission, meaning that PDUs are droppped with + * a user-defined probability. + */ +class ErrorModelDraw +: public ErrorModel +{ +public: + /// Creation via static method to enforce shared_ptr usage + static ErrorModelPtr create( base::Simulation& sim, const data::Label& label, + double probability ); + + /// Destruction + virtual ~ErrorModelDraw(); + + /** + * @brief Implementation of the error model interface + * @param p The PDU that the error model is applied to + * @return @true if the PDU may be transmitted + * + * The implementation of the error model interface simply calls + * @c sample on the internal @c Draw object, which either returns 0 or 1. + * These value appear with the given probability and are used to + * decide whether PDUs may be received at their destination or not. + */ + virtual bool apply( PduPtr p ); + +private: + /// Draw object for getting a stream of ones and zeros + odemx::random::Draw draw_; + +private: + /// Construction private, use @c create instead + ErrorModelDraw( base::Simulation& sim, const data::Label& label, double probability ); +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_ERRORMODELDRAW_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Layer.h b/odemx-lite/include/odemx/protocol/Layer.h new file mode 100644 index 0000000000000000000000000000000000000000..fe5c5fba012368715979afb981ccb3a65eb66d22 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Layer.h @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Layer.h + * @author Ronald Kluth + * @date created at 2009/10/13 + * @brief Declaration of class odemx::protocol::Layer + * @sa Layer.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_LAYER_INCLUDED +#define ODEMX_PROTOCOL_LAYER_INCLUDED + +#include <odemx/data/Producer.h> + +//---------------------------------------------------------forward decalarations + +namespace odemx { +namespace protocol { + +class ServiceProvider; +class Sap; + +//----------------------------------------------------------header decalarations + +/** + * @brief Models the layers of a protocol stack and contains service providers + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Stack odemx::protocol::ServiceProvider odemx::protocol::Sap + * + * ODEMx protocol stacks consist of a number of layers that each offer services + * to the layer above. The services are implemented by ServiceProvider subclasses, + * while access to them is provided via service access points (SAPs). + * + * A Layer can hold an arbitrary number of ServiceProviders while making all + * of their SAPs visible to the layers above and below in the stack. Layers + * always own their ServiceProvider objects and delete them automatically upon + * destruction. + */ +class Layer +: public data::Producer +{ +public: + /// Vector type to store pointers to all kinds of service providers + typedef std::vector< ServiceProvider* > ServiceProviderVec; + /// Map type to associate service types with suitable SAPs + typedef std::map< std::string, Sap* > SapMap; + + /// Construction + Layer( base::Simulation& sim, const data::Label& label ); + + /** + * @brief Destruction + * + * As the Layer owns all ServiceProviders, it deletes them here. + */ + virtual ~Layer(); + + /** + * @brief Register a new service provider object + * @param sp The new service provider + * + * This layer is set as the service provider's layer so that it may + * have access to SAPs offered by the upper and lower layer. + * In addition, all SAPs of the new service provider are added to the + * SAP map of this layer so they can be retrieved by name. Finally, + * the service provider is stored in an internal vector. + */ + void addServiceProvider( ServiceProvider* sp ); + + /// Get read access to the internal vector holding service providers + const ServiceProviderVec& getServiceProviders() const; + + /// Get a pointer to an SAP by providing its name + Sap* getSap( const std::string& sap ) const; + + /// Get a reference to the map containing all registered SAPs + SapMap& getSaps(); + + /// Get access to the upper layer, usually to access its SAPs + Layer* getUpperLayer() const; + + /// Get access to the lower layer, usually to access its SAPs + Layer* getLowerLayer() const; + + /** + * @brief Set the layer above this one in the stack's hierarchy + * @param layer The layer above + * + * This method is usually not called manually. It is used when adding + * layers to the protocol stack. In that way, adjacent layers get + * connected automatically. + */ + void setUpperLayer( Layer* layer ); + + /** + * @brief Set the layer below this one in the stack's hierarchy + * @param layer The layer above + * + * This method is usually not called manually. It is used when adding + * layers to the protocol stack. In that way, adjacent layers get + * connected automatically. + */ + void setLowerLayer( Layer* layer ); + + /** + * @brief Add an SAP to the layer + * @param sap The SAP object to be registered + * + * This method is usually not called manually. It is used when adding + * service providers to make their SAPs known to users of this layer. + */ + void addSap( Sap* sap ); + + /** + * @brief Remove a registered SAP from the layer + * @param sap Name of the SAP object to be removed + * + * This method is usually not called manually. It is used when SAPs + * are removed from service providers in order to notify the layer that + * an SAP is no longer available. + */ + bool removeSap( const std::string& sap ); + +protected: + /// Stores all of the layer's service providers + ServiceProviderVec serviceProviders_; + /// Stores all of the SAPs offered by the layer's service providers + SapMap saps_; + /// Stores a pointer to the upper layer in the hierarchy + Layer* upperLayer_; + /// Stores a pointer to the lower layer in the hierarchy + Layer* lowerLayer_; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_LAYER_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Medium.h b/odemx-lite/include/odemx/protocol/Medium.h new file mode 100644 index 0000000000000000000000000000000000000000..83149a4bafd872052c69c64d95355ab243a0ccc0 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Medium.h @@ -0,0 +1,263 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Medium.h + * @author Ronald Kluth + * @date created at 2009/11/01 + * @brief Declaration of class odemx::protocol::Medium + * @sa Medium.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_MEDIUM_INCLUDED +#define ODEMX_PROTOCOL_MEDIUM_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/base/Event.h> +#include <odemx/protocol/Device.h> +#include <odemx/protocol/Pdu.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace protocol { + +class ErrorModel; + +//-----------------------------------------------------------header declarations + +/** + * @brief Models the transmission medium used by devices to transmit data + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Device odemx::protocol::ErrorModel + * + * The Medium manages the topology of a network in the form of links between + * Device objects. All devices must be registered to a medium in order to + * be able to send PDUs to their neighbor nodes. Whenever a device transmits + * data, the medium is responsible for scheduling the corresponding TransmissionStart + * and TransmissionEnd events for all neighbors of a node. + * + * Furthermore, an error model can be assigned to the medium so that arbitrary + * transmission failures may be modeled in a uniform way. If more fine-grained + * control is required, each link can also be assigned an error model. + * + */ +class Medium +: public data::Producer +{ +public: + /// Map type to associate addresses with device objects + typedef std::map< Device::AddressType, Device* > DeviceMap; + + /// Pointer type to manage ErrorModel object lifetime + typedef std::shared_ptr< ErrorModel > ErrorModelPtr; + + /// Structure containing the link properties delay and error model + struct LinkInfo + { + /// Defaut construction + LinkInfo(); + /// Construction with link delay and error model + LinkInfo( base::SimTime delay, ErrorModelPtr errorModel ); + /// The specified link delay + base::SimTime delay_; + /// The provided error model for this link + ErrorModelPtr errorModel_; + }; + + /// Map type associating device pointers with link info objects + typedef std::map< Device*, LinkInfo > LinkInfoMap; + + /// Map type associating device pointers with a link info map (i.e. links to neighbors) + typedef std::map< Device*, LinkInfoMap > TopologyMap; + + /// Construction + Medium( base::Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~Medium(); + + /** + * @brief Notify all neighbors of the device that it will start sending + * @param sender The device that starts a transmission + * + * This method is used to signal the start of a transmission to all + * neighbor nodes in the network. This is implemented by scheduling + * TransmissionStart events after the specified link delay for each + * registered link of the sender device. + */ + void signalTransmissionStart( Device* sender ); + + /** + * @brief Notify all neighbors of the device about the transmission end and deliver PDUs + * @param sender The device that finished its transmission + * @param p The PDU to be delivered to receiving nodes + * + * This method is used to signal the end of a transmission to all + * neighbor nodes in the network. This can either mean that the transmission + * was aborted, for example due o collision detection, or that it was + * transmitted to the medium successfully (which not necessarily means + * the PDU arrives at the receivers). + * + * Like @c signalTransmissionStart, this method also schedules events, + * this time of type TransmissionEnd, after the specified link delay + * for each registered link of the sender device. This kind of events + * always transports a PDU, which may or may not contain valid data. + * + * The latter fact is due to the usage of the links' error models. + * If the link has no error model, or the message passes it, then a valid + * PDU is delivered. However, the error model may still have corrupted the + * contained data. + */ + void signalTransmissionEnd( Device* sender, PduPtr p ); + + /** + * @brief Set the default error model of the medium + * @param errorModel The default error model of the medium + * + * During construction the medium is not assigned an error model. + * So this method must be used in order to activate that functionality. + * The provided error model will then be used as the default error + * model that all Links are initialized with, unless a different error + * model is provided when adding the link. + */ + void setErrorModel( ErrorModelPtr errorModel ); + + /** + * @brief Add a link between two devices + * @param srcAddr Address of the sender device + * @param destAddr Address of the receiver device + * @param delay Time it takes to send data over this link + * @param duplex Determines whether to add the link in both directions + * @param errorModel Provides a link-specific error model + * @return @c true if the link was successfully added + * + * This method wraps the other @c addLink overload by first retrieving + * the pointers to registered devices and then calling the overload. + * By default, the link is unidirectional. Supply @c true for parameter + * @c duplex to have the link added in both directions. + */ + bool addLink( const Device::AddressType& srcAddr, + const Device::AddressType& destAddr, + base::SimTime delay, bool duplex = false, + ErrorModelPtr errorModel = ErrorModelPtr() ); + + /** + * @brief Add a unidirectional link between two devices + * @return @c false if the given devices are the same + * + * This method writes a link info entry to the topology map. If there is a + * pre-existing link, its properties will be overwritten. This method + * also automatically sets the medium for @c src, or both devices in + * case of duplex mode. + */ + bool addLink( Device* src, Device* dest, base::SimTime delay, + ErrorModelPtr errorModel = ErrorModelPtr() ); + + /** + * @brief Remove a link between two devices + * @param srcAddr Address of the sender device + * @param destAddr Address of the receiver device + * @param duplex Determines whether to remove the link in both directions + * + * This method simply retrieves the device pointers and + * calls the overload. If @c duplex is true, the link will be + * removed in both directions. + */ + void removeLink( const Device::AddressType& srcAddr, + const Device::AddressType& destAddr, bool duplex = false ); + + /** + * @brief Remove a unidirectional link between two devices + * + * The method tries to find the given nodes in the topology map + * end erases the link information between them. + */ + void removeLink( Device* src, Device* dest ); + + /** + * @brief Register a new network device by its address + * @param address The address for the device + * @param device The device object + * @return @c true if the device was inserted successfully + * + * This method sets the device's address, and also registers this medium + * object with the device. Finally, it inserts the address and the device + * pointer in the device lookup map. + */ + bool registerDevice( const Device::AddressType& address, Device& device ); + + /// Get access to a registered device + Device* getDevice( const Device::AddressType& address ) const; + + /// Get read access to the topology map + const TopologyMap& getTopology() const; + + /// Get read access to the device map + const DeviceMap& getDevices() const; + + /// Keep collision statistics + void collision() const; + +protected: + /// Stores the links between all nodes in the network + TopologyMap topology_; + /// Associates all registered device addresses with Device objects + DeviceMap devices_; + /// The default error model to be set for links if none is provided + ErrorModelPtr defaultErrorModel_; + +protected: + /// Event type for delayed PDU delivery, models the start of a transmission + class TransmissionStart + : public base::Event + { + public: + /// Construction + TransmissionStart( base::Simulation& sim, const data::Label& label, + Device& device ); + + /// Increases the receiving device's transmission count + virtual void eventAction(); + private: + Device* device_; + }; + + /// Event type for delayed PDU delivery, models the end and delivery of a transmission + class TransmissionEnd + : public base::Event + { + public: + /// Construction + TransmissionEnd( base::Simulation& sim, const data::Label& label, + Device& device, PduPtr p ); + + /// Delivers a PDU at the receiving device and decreases its transmission count + virtual void eventAction(); + private: + Device* device_; + PduPtr pdu_; + }; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_MEDIUM_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Pdu.h b/odemx-lite/include/odemx/protocol/Pdu.h new file mode 100644 index 0000000000000000000000000000000000000000..ea885caeff6f5a5594a9fc3ca0f20e1b5ab60fb5 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Pdu.h @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Pdu.h + * @author Ronald Kluth + * @date created at 2009/10/31 + * @brief Declaration of interface odemx::protocol::Pdu + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_PDU_INCLUDED +#define ODEMX_PROTOCOL_PDU_INCLUDED + +#include <cstddef> +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + +namespace odemx { +namespace protocol { + +class Pdu; + +/// Smart pointer type to manage the lifetime of PDUs +typedef std::shared_ptr< Pdu > PduPtr; + +/** + * @brief Base class for all protocol data unit types + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Sap odemx::protocol::ServiceProvider + * + * All message queues in ODEMx requires the same polymorphic base type + * in order to forward arbitrary messages. Therefore, protocol data units + * (PDUs) are represented by this class. The data buffers are held by SAPs + * and read by service providers or service users. + * + * The interface defined for PDU types is simple. ODEMx needs to know the + * size of the data unit when it is transmitted via medium, and the PDUs + * must be cloneable in order to avoid side effect when the same PDU + * is forwarded to multiple receivers at once. + */ +class Pdu +{ +public: + /// Destruction + virtual ~Pdu() {} + + /** + * @brief Create a copy of a PDU object + * @return Pointer to a copy of the PDU object + * @see odemx::protocol::Medium + * + * All message types to be used in ODEMx protocol simulations must + * implement a clone method. Sending the same message to a number + * of different receivers requires that each of them work with their + * own copy of the message because it may be altered on its way through + * a network. Merely copying the pointer would likely result in unintended + * changes leading to subtle errors. This method is thus used by the medium + * whenever PDUs are sent to receivers. + */ + virtual PduPtr clone() const = 0; + + /** + * @brief Get the size of a PDU + * @return Size of the PDU + * @see odemx::protocol::Device + * + * Determining the time it takes to transmit a message via a medium + * requires knowledge of the message size and the bitrate at which a + * device can send. The latter factor may vary depending on quality of + * service parameters and external influences. Therefore, devices require + * the message size instead of a fixed time duration value in order to + * compute the amount of time it takes to transmit a given message. + * + * @note The default implementation returns 0 + */ + virtual std::size_t getSize() const = 0; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_PDU_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Sap.h b/odemx-lite/include/odemx/protocol/Sap.h new file mode 100644 index 0000000000000000000000000000000000000000..a217a815b23e1ae9fa34deb0378c6789d9b98912 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Sap.h @@ -0,0 +1,174 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Sap.h + * @author Ronald Kluth + * @date created at 2009/10/13 + * @brief Declaration of class odemx::protocol::Sap + * @sa Sap.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_SAP_INCLUDED +#define ODEMX_PROTOCOL_SAP_INCLUDED + +#include <odemx/protocol/Pdu.h> +#include <odemx/synchronization/Port.h> + +#include <deque> +#include <string> + +//----------------------------------------------------------forward declarations + +namespace odemx { + +namespace base { class Process; } + +namespace protocol { + +class ServiceProvider; + +//---------------------------------------------------------- header declarations + +/** + * @brief Service access point (SAP) implementation for protocol service providers + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::ServiceProvider odemx::protocol::Layer odemx::protocol::Stack + * + * In ODEMx, protocol services are modeled by ServiceProvider implementations. + * SAPs provide a decoupled interface to the services offered by a protocol layer. + * By offering access through the same interface, service providers can easily + * be exchanged, allowing for top-down refinement by first using an abstract + * Service implementation that may then be replaced by a more detailed Entity or + * device. The communication of the application layer with the protocol stack + * is also implemented with SAPs. Therefore, the protocol stack itself is + * replaceable, for example by a simpler Service implementation. + * + * Sap is compatible with the wait-alert concept that is based on Memory + * implementations. For this reason, class Sap has an internal buffer + * that is derived from odemx::synchronization::PortHeadT. + */ +class Sap +{ +public: + + /** + * @brief Internal buffer interface + * + * The SAP buffer is implemented using an odemx::synchronization::PortT. This class + * provides the read interface to the buffer. It is required in order + * to query the alerting PortHeadT for its owning SAP. + */ + class BufferHead: public synchronization::PortHeadT< PduPtr > + { + public: + /// Smart pointer type to manage oject lifetime + typedef std::shared_ptr< BufferHead > Ptr; + + /// Creation via static method to enfore shared_ptr usage + static Ptr create( base::Simulation& sim, const data::Label& label, Sap& sap ); + + /// SAP access + Sap& getSap() const; + + private: + /// Pointer to the owning SAP + Sap* sap_; + private: + /// Construction private, use @c create instead + BufferHead( base::Simulation& sim, const data::Label& label, Sap& sap ); + }; + + /** + * @brief Construction + * @param sim The simulation context + * @param label The label of the owning service provider + * @param name The name to be used for accessing the SAP + * + * The constructor initializes the internal buffer, as well as its + * read and write interfaces (head and tail). + */ + Sap( base::Simulation& sim, const data::Label& label, const std::string& name ); + + /// Destruction + virtual ~Sap(); + + /// Get the name of the SAP + const std::string& getName() const; + + /** + * @brief Get a pointer to the buffer read interface + * + * This method is needed when SAPs are used in calls of Process::wait(), + * which expects a number of IMemory pointers to be passed to it. As soon + * as data becomes available at an SAP, the waiting Process is reactivated + * and can use the BufferHead to check which SAP awoke it. + */ + BufferHead* getBuffer() const; + + /** + * @brief Send interface for service users + * @param p The data unit to be written to the SAP + * + * This method is used to put data into the SAP's buffer. If there is + * a service provider waiting for input on this SAP, that process will + * immediately activated in order to consume the data. + */ + void write( PduPtr p ); + + /** + * @brief Receive interface for service users + * @return The first data unit stored in the SAPs buffer + * + * This is a blocking call to the SAP's buffer. If there is no data + * available, the calling Process will be put into a wait state + * until @c write is called on the SAP. + */ + PduPtr read(); + +private: + // The name must not be unique, i.e. no Label, because all ServiceProvider + // objects expect to access SAPs by the same names, not unique ones. + /// Name of the SAP for access by service providers + std::string name_; + /// Input buffer read interface + BufferHead::Ptr queueHead_; + /// Input buffer write interface + BufferHead::TailPtr queueTail_; + +public: + // TODO: turn this into a comparator for std::set and replace SAP vectors with sets + + /// Functor for use with std algorithms to find SAPs by name + struct MatchName + { + const std::string& name_; + MatchName( const std::string& name ): name_( name ) {} + bool operator()( Sap* sap ) const + { + return sap->getName() == name_; + } + }; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_SAP_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Service.h b/odemx-lite/include/odemx/protocol/Service.h new file mode 100644 index 0000000000000000000000000000000000000000..f410434e185d56880d134696f403c50758a11394 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Service.h @@ -0,0 +1,302 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Service.h + * @author Ronald Kluth + * @date created at 2009/10/12 + * @brief Declaration of class odemx::protocol::Service + * @sa Service.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_SERVICE_INCLUDED +#define ODEMX_PROTOCOL_SERVICE_INCLUDED + +#include <odemx/protocol/ServiceProvider.h> +#include <odemx/protocol/Sap.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace protocol { + +class ErrorModel; + +//-----------------------------------------------------------header declarations + +/** + * @brief Base class for modeling simple protocol services + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Sap odemx::protocol::Stack odemx::protocol::Layer odemx::protocol::ErrorModel + * + * A layer in the protocol stack usually offers a specific functionality to + * its users as services. An access interface is provided through so-called + * service access points (SAP). Users pass service primitives + * (i.e. commands and data) to specific SAPs in order to make use of a + * service. The functionality the service offers is implemented by service + * providers, active objects within the layers of a stack. One such class is + * Service. + * + * This class provides the basis for the implementation of a simple service. + * Service is intended to be used inn one of two ways. It can either replace + * a stack and provide a very simple communication layer for nodes, or it + * can be used in the bottom layer of a protocol stack in order to simplify + * the transmission aspect of the network model. All Service objects are + * directly linked in order to abstract from the network topology. + * All service objects in a simulation are associated with addresses upon + * registration. Registering a service object means that a pointer to it + * is stored in a map, and it can be accessed by providing the service address. + * Subclasses need to define the pure virtual methods @c handleSend and + * @c handleReceive in order to define the service behavior. + * + * Since Service objects may be used as a replacement for @c Stack objects, + * they also provide the same functionality with regard to receive SAPs. Users + * may create output SAPs they can use to listen for received data by calling + * the method @c addReceiveSap. + */ +class Service +: public ServiceProvider +{ +public: + /// Address type to identify users + typedef std::string AddressType; + /// Map type to associate user addresses with service objects + typedef std::map< AddressType, Service* > AddressMap; + + /** + * @brief Construction + * @param sim The simulation context + * @param label The label of the object + * + * The constructor initializes an internal SAP that is needed for + * receiving data from peer service objects. Since services are service + * providers, they also just listen for input and wait. They must therefore + * be awakened by an internal SAP when data is received from a peer. This + * functionality is analogous to that of class Device. + */ + Service( base::Simulation& sim, const data::Label& label ); + + /** + * @brief Destruction + * + * All receive SAPs that were added as listening interfaces by an + * application layer are automatically deleted. + */ + virtual ~Service(); + + /** + * @name Service user registration and access + * @{ + */ + /** + * @brief Register a user with the service in order to receive messages + * @param address The address to use for accessing the given service + * @param service The service object to be registered + * @return @c true if the map insertion was successful + * + * Service objects are always directly connected within a simulation. + * Therefore, they are all simply registered with a static map and can + * be accessed by their addresses. + */ + static bool registerService( const AddressType& address, Service& service ); + + /** + * @brief Remove a service from the registration map to make a node unavailable + * @param address The address of the service to be removed from the map + * @return @c true of if the removal was successful + * + * Since the nodes of a network may dynamically enter and leave, this method + * provides a means to make Service peers unavailable by simply removing the + * map entries. + */ + static bool removeService( const AddressType& address ); + + /// Get read access to the map holding all registered users + static const AddressMap& getAddressMap(); + + /** + * @brief Get a pointer to a registered Service object + * @param peer The address under which the peer service is registered + * @return Pointer to the peer object, or 0 if not found + * + * Since the service is an abstraction of the protocol stack or the + * transmission device, and not all configuration data may be contained + * in transmitted messages, it may sometimes be necessary to influence + * the state of a particular service object internally. This method + * provides the means to retrieve any registered service object. + */ + static Service* getPeer( const AddressType& peer ); + + /** + * @brief Set the address of a Service object + * + * Normally, there is no need to use this method manually. Upon registration + * the service will automatically receive the address provided + * in the call to @c registerService. + */ + void setAddress( const AddressType& addr ); + + /// Get the address of the service object + const AddressType& getAddress() const; + //@} + + /** + * @brief Add an SAP from which to receive data + * @param name The name of the SAP to be created + * @return A pointer to the SAP object + * + * When a Service class is used in place of a Stack, it must be usable + * in the same manner. Since stacks allow for the creation of listening + * SAPs, services do this as well. + * + * @note These objects are managed internally. There is no need + * call delete on them. + */ + Sap* addReceiveSap( const std::string& name ); + + /// Get access to a receive SAP owned by the service + Sap* getReceiveSap( const std::string& name ); + + /** + * @brief Send a data unit to another registered Service object + * @param peer The service's address + * @param p The data unit to be transmitted + * @return @c true if the receiver was found in the map + * + * This method is used to directly send PDUs from one node to another. + * It looks up the peer in the registration map and calls @c receive + * on the service object. A warning will be issued + * if the peer is not found. + */ + bool send( const AddressType& peer, PduPtr p ) const; + + /** + * @brief Pass a message from the network to the upper layer + * @param sapName The SAP to which to pass the data unit + * @param p The data unit to pass on + * + * This method simply looks up the SAP in the upper layer, or the receive + * SAPs. It then writes the given data unit to it. A warning will be issued + * if the SAP is not found. + */ + bool pass( const std::string& sapName, PduPtr p ); + + /** + * @brief Set the error model for the Service class + * @param em The error model to be used by the Service implementation + * + * Since this class is only a simple implementation of a transmission + * service, it can also only provide a simple means of modeling + * errors in the transmission activities. + * + * Only one ErrorModel implementation can be set per Service class + * because it is implemented with a static member. It is checked whenever + * a registered service object receives data from a peer. This way, + * PDUs can be filtered or altered during the transmission period. + */ + static void setErrorModel( std::shared_ptr< ErrorModel > em ); + +protected: + /** + * @name Input handling, to be defined by subclasses + * @{ + */ + /** + * @brief Implements the service functionality for sending data + * @param sapName The SAP used to input the data + * @param p The data unit to be transmitted to a peer + * + * Whenever data is provided by an SAP other than the internal receive + * SAP, this pure virtual method is called with the name of the SAP + * and the PDU to send. Every service must implement this method in + * order to specify what data is to be transmitted and how long the + * waiting period is. Usually, this method calls @c send. + */ + virtual void handleSend( const std::string& sapName, PduPtr p ) = 0; + + /** + * @brief Implement the service functionality for message reception + * @param p The data unit received from the medium + * + * This method gets called whenever data from a peer arrives through + * the internal receive SAP. The service must implement this method to + * define if and how data is to be passed to the upper layer or not. + * Usually, this method calls @c pass. + */ + virtual void handleReceive( PduPtr p ) = 0; + + /// Implementation of the service provider interface + virtual void handleInput( const std::string& sap, PduPtr pdu ); + //@} + + /** + * @brief Put a data unit into the service's receive SAP + * + * This method should not be called manually. It is part of the interaction + * between peers. As such, it is called from with the method @c send. + */ + void receive( PduPtr p ); + +protected: + /// Stores the address of a service object + AddressType address_; + /// Internal SAP for message reception from peers + Sap* receiveSap_; + /// Stores all registered output SAPs + SapVec outputSaps_; + /// Associates addresses of service users with pointers to their service objects + static AddressMap services_; + /// Manages a pointer to the error model, if one is set + static std::shared_ptr< ErrorModel > errorModel_; +}; + +} } // namespace odemx::protocol + +// how to implement global user storage for multiple service classes in the same simulation: +// make the static map dependent on the derived type of the service +// each derived type gets its own user storage generated by the compiler +// when the templates get instantiated +// service must be implemented via CRTP: +// class DerivedService: public ServiceT< DerivedService > {}; +/* +template < typename > class ServiceUserStorage; + +template < typename DerivedT > +class ServiceT +{ +public: // service impl + static ServiceUserStorage< DerivedT > userStorage_; +}; + +template < typename DerivedServiceT > +class ServiceUserStorage +{ +public: + typedef std::string AddressType; + typedef std::map< AddressType, Service* > UserMap; + static UserMap users_; +}; + +template < typename DerivedServiceT > +ServiceUserStorage< DerivedServiceT >::UserMap ServiceUserStorage< DerivedServiceT >::users_; +*/ + +#endif /* ODEMX_PROTOCOL_SERVICE_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/ServiceProvider.h b/odemx-lite/include/odemx/protocol/ServiceProvider.h new file mode 100644 index 0000000000000000000000000000000000000000..beef36ba408e6359a47a677acdc74a30fffeeaa6 --- /dev/null +++ b/odemx-lite/include/odemx/protocol/ServiceProvider.h @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ServiceProvider.h + * @author Ronald Kluth + * @date created at 2009/10/29 + * @brief Declaration of class odemx::protocol::ServiceProvider + * @sa ServiceProvider.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_SERVICEPROVIDER_INCLUDED +#define ODEMX_PROTOCOL_SERVICEPROVIDER_INCLUDED + +#include <odemx/base/Process.h> +#include <odemx/protocol/Pdu.h> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace protocol { + +class Layer; +class Sap; + +//-----------------------------------------------------------header declarations + +/** + * @brief Abstract base class for service-implementing classes + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Sap odemx::protocol::Service odemx::protocol::Entity odemx::protocol::Device + * + * A service usually offers a specific functionality to its users. An interface + * to a service is provided through a so-called service access point (SAP). + * Users pass service primitives (i.e. commands with data) to the SAP in order + * to make use of the service. In ODEMx, service provider implementations + * are the active components in the layers of the protocol stack. Thus + * they are derived from class Process. + * + * Class ServiceProvider provides the basis for the implementation of service + * providers. The base functionality includes a vector for an arbitrary number + * of SAPs and a pointer the layer of the stack which holds the service provider. + * + * ServiceProvider objects own their SAPs. Their process behavior is defined as + * waiting state until data is ready at one of the SAPs. As soon as data becomes + * available, the Process is activated and calls the pure virtual function + * @c handleInput. Subclasses must define this to specifiy the service + * implementation. + */ +class ServiceProvider +: public base::Process +{ +public: + /// Vector type to hold pointers to SAPs + typedef std::vector< Sap* > SapVec; + /// Destruction, deletes all Sap objects owned by the ServiceProvider + virtual ~ServiceProvider(); + + /// Set the owning layer of this service provider + void setLayer( Layer* layer ); + /// Access the layer, may return 0 if the layer is not set + Layer* getLayer() const; + + /** + * @brief Create and add an SAP to the service provider + * @param name The name of the SAP to be created + * @return Pointer to the SAP of that name + * + * If the SAP already exists, a warning will be issued and the existing + * object returned. Otherwise, a new Object will be created and added + * to a vector. If a layer is set, the SAP will also be regstered + * with the layer to make it available to the upper and lower layers. + */ + Sap* addSap( const std::string& name ); + + /** + * @brief Remove an SAP from the service provider + * @param name The name of the SAP + * @return @c true if successful, @c false if not found + * + * This method removes an SAP from the ServiceProvider and also + * from the layer, if one is set. + */ + bool removeSap( const std::string& name ); + + /// Access any SAP by name, returns 0 if the name was not found + Sap* getSap( const std::string& name ) const; + + /// Get a list of all SAPs owned by this service provider + const SapVec& getSaps() const; + +protected: + /** + * @brief Implement the service functionality + * @param sapName The SAP from which input was received + * @param pdu The protocol data unit read from the SAP + * + * This function defines the behavior of a service provider when + * a PDU is input through one of its SAPs. Since the name is provided + * as argument, the service provider can choose the appropriate action + * for the requested service. + */ + virtual void handleInput( const std::string& sapName, PduPtr pdu ) = 0; + + /** + * @brief Construction + * + * The constructor automatically activates the process so that its + * @c main function gets called as soon as the simulation run starts. + */ + ServiceProvider( base::Simulation& sim, const data::Label& label ); + + /** + * @brief Process behavior definition + * + * The ServiceProvider enters a wait state until it receives input. + * It then calls @c handleInput and returns to the wait state after that + * function call returns. + */ + virtual int main(); + +protected: + /// Stores a pointer to the layer this service provider belongs to + Layer* layer_; + /// Stores pointers to all SAPs owned by the service provider + SapVec saps_; + /// Stores pointers to the SAP's buffers (subclasses of Memory) for wait-alert + synchronization::IMemoryVector sapQueues_; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_SERVICEPROVIDER_INCLUDED */ diff --git a/odemx-lite/include/odemx/protocol/Stack.h b/odemx-lite/include/odemx/protocol/Stack.h new file mode 100644 index 0000000000000000000000000000000000000000..529c630fb4c837d147a5cf2a1398f408292a6eba --- /dev/null +++ b/odemx-lite/include/odemx/protocol/Stack.h @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Stack.h + * @author Ronald Kluth + * @date created at 2009/10/16 + * @brief Declaration of class odemx::protocol::Stack + * @sa Stack.cpp + * @since 3.0 + */ + +#ifndef ODEMX_PROTOCOL_STACK_INCLUDED +#define ODEMX_PROTOCOL_STACK_INCLUDED + +#include <odemx/data/Producer.h> + +#include <map> +#include <vector> + +//----------------------------------------------------------forward declarations + +namespace odemx { +namespace protocol { + +class Sap; +class Layer; +class Pdu; + +//-----------------------------------------------------------header declarations + +/** + * @brief A class for assembling protocol stacks from layers and service providers + * @ingroup protocol + * @author Ronald Kluth + * @since 3.0 + * @see odemx::protocol::Layer odemx::protocol::Entity odemx::protocol::Service odemx::protocol::Device + * + * Protocol stacks are composed of layers that each provide different services + * to the layer above. Stack is the class that allows gluing these layers + * together. Registered layers are owned by the stack and kept in a vector. + * The registration order is important because the layers' internal pointers + * to adjacent layers (upper/lower) are set during this phase. + * + * As the stack provides the means to transmit data between the applications + * running on network nodes, it must also provide a means to listen for + * incoming data. This is achieved by creating receive SAPs. + * + * @note It is not always necessary to use a complete protocol stack in order + * to model node communication in a network. The simplest way to achieve this + * is to use a Service implementation, which can be used as a replacement + * for Stack objects as it includes the same interface. + */ +class Stack +: public data::Producer +{ +public: + /// Vector type to hold pointers to protocol layers + typedef std::vector< Layer* > LayerVec; + + /** + * @brief Construction + * @param sim The simulation context + * @param label The label of the object + * + * The constructor initializes an internal layer that is used for storing the + * receive SAPs that stack users can listen on. + */ + Stack( base::Simulation& sim, const data::Label& label ); + + /** + * @brief Destruction + * + * The destructor deletes all receive SAPs and all layers owned by the stack. + */ + virtual ~Stack(); + + /** + * @brief Get access to an SAP from the top layer of the stack hierarchy + * + * In order to use a protocol stack, data must be passed to it by writing + * data units to an SAP. This method is used to retrieve SAPs of the top + * layer in the stack hierarchy. The service providers of the layers will + * then take care of the transmission procedure. + */ + Sap* getSap( const std::string& name ) const; + + /** + * @brief Add a layer to the protocol stack + * + * Protocol stacks are composed from layers. Thus, in order to configure a + * stack, one must first create the layers with appropriate service + * providers and then add them to the stack. The layers must be added in + * order from top to bottom. + */ + void addLayer( Layer* layer ); + + /** + * @brief Get a reference to the vector containing all registered layers + * @return Reference to the internal layer vector + * @note Provided for testing purposes + */ + const LayerVec& getLayers() const; + + /** + * @brief Add a new SAP to the stack in order to receive output + * @return Pointer to the SAP object, may be newly created or alreaady existing + * + * Users of the stack may need to add SAPs from which to receive data. + * These SAPs are managed by the Stack so users do not need to delete them. + * If the addition of an existing SAP is requested, the method will + * issue a warning message. + */ + Sap* addReceiveSap( const std::string& name ); + + /** + * @brief Get a pointer to one of the protocol stack's SAPs + * @return Pointer to the requested SAP object, or 0 if the SAP does not exist + * + * Users of the stack can get access to receive SAPs by name in order + * to listen for the arrival of data. + */ + Sap* getReceiveSap( const std::string& name ) const; + +private: + /// Stores the layers that compose the protocol stack + LayerVec layers_; +}; + +} } // namespace odemx::protocol + +#endif /* ODEMX_PROTOCOL_STACK_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/ContinuousConst.h b/odemx-lite/include/odemx/random/ContinuousConst.h new file mode 100644 index 0000000000000000000000000000000000000000..18465359c1333e5c4d2efbb2fbadaddca61ea650 --- /dev/null +++ b/odemx-lite/include/odemx/random/ContinuousConst.h @@ -0,0 +1,83 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file ContinuousConst.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::ContinuousConst + */ + +#ifndef CONTINUOUSCONST_H_ +#define CONTINUOUSCONST_H_ + +#include <odemx/random/ContinuousDist.h> + +namespace odemx { +namespace random { + +/** \class ContinuousConst + + \ingroup rdist + + \author Ralf Gerstenberger + + \brief Constant number generator + + \note Rconst from ODEM + + \note supports Report + + ContinuousConst provides a constant number through the + ContinuousDist interface. + + \since 1.0 +*/ +class ContinuousConst +: public ContinuousDist +{ +public: + + /** + \brief Construction with user-defined DistContext (i.e. Simulation) + \param label + Label of the generator + \param c + Pointer to DistContext object + \param d + constant double returned by sample() + */ + ContinuousConst( base::Simulation& sim, const data::Label& label, double value ); + + /// Destruction + virtual ~ContinuousConst(); + + /// Get number + virtual double sample(); + + /// Get parameter d + double getValue(); + +private: + const double value_; +}; + +} } // namespace odemx::random + +#endif /* CONTINUOUSCONST_H_ */ diff --git a/odemx-lite/include/odemx/random/ContinuousDist.h b/odemx-lite/include/odemx/random/ContinuousDist.h new file mode 100644 index 0000000000000000000000000000000000000000..7fbe9afb4d5e38ca7c41b66b24aba8d819a70bd3 --- /dev/null +++ b/odemx-lite/include/odemx/random/ContinuousDist.h @@ -0,0 +1,93 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ContinuousDist.h + + \author Ralf Gerstenberger + + \date created at 2003/05/09 + + \brief Declaration of odemx::random::ContinuousDist + + \sa ContinuousDist.cpp + + Continuous random number generator. + + \since 1.0 +*/ + +#ifndef ODEMX_RDIST_INCLUDED +#define ODEMX_RDIST_INCLUDED + +#include <odemx/random/Dist.h> + +namespace odemx { +namespace random { + +/** + \defgroup rdist Continuous distributions + \ingroup random + + A group of random number generators which produce continuous (double) + random numbers of different distributions. +*/ + +/** \interface ContinuousDist + + \ingroup rdist + + \author Ralf Gerstenberger + + \brief Interface for continuous distributions + + %ContinuousDist declares the 'double sample()' method for continuous + distribution classes. All derived classes implement this + method to provide the random numbers in different distributions. + + \since 1.0 +*/ +class ContinuousDist +: public Dist +{ +public: + + /** + \brief Construction with user-defined DistContext (i.e. Simulation) + \param label + Label of the generator + \param c + pointer to DistContext object + */ + ContinuousDist( base::Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~ContinuousDist(); + + /** + \brief Get next random number + + This function returns the next random number. + It is implemented in derived classes which generate + random numbers in different distributions. + */ + virtual double sample() = 0; +}; + +} } // namespace odemx::random + +#endif diff --git a/odemx-lite/include/odemx/random/DiscreteConst.h b/odemx-lite/include/odemx/random/DiscreteConst.h new file mode 100644 index 0000000000000000000000000000000000000000..4647c2227fb83e1e24d65dac3c998e2fdb448408 --- /dev/null +++ b/odemx-lite/include/odemx/random/DiscreteConst.h @@ -0,0 +1,81 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file DiscreteConst.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::DiscreteConst + */ + +#include <odemx/random/DiscreteDist.h> + +namespace odemx { +namespace random { + +/** \class DiscreteConst + + \ingroup idist + + \author Ralf Gerstenberger + + \brief Constant number generator + + \note Iconst from ODEM + + \note supports Report + + DiscreteConst provides a constant integer number through the + DiscreteDist interface. The constant number is set in the + constructor. + + \since 1.0 +*/ +class DiscreteConst +: public DiscreteDist +{ +public: + /** + \brief Construction for user-defined DistContext (i.e. Simulation) + \param title + Label of the generator + \param c + RNG Context + \param i + constant integer returned by sample() + + The parameter i defines the number returned + by this pseudo generator. + */ + DiscreteConst( base::Simulation& sim, const data::Label& label, int value ); + + /// Destruction + virtual ~DiscreteConst(); + + /// Get number + virtual int sample(); + + /// Get the constant value + int getValue(); + +private: + const int value_; +}; + +} } // namespace odemx::random diff --git a/odemx-lite/include/odemx/random/DiscreteDist.h b/odemx-lite/include/odemx/random/DiscreteDist.h new file mode 100644 index 0000000000000000000000000000000000000000..5f77b7d1faa2f41c257ff6aaf80ab749b7813e29 --- /dev/null +++ b/odemx-lite/include/odemx/random/DiscreteDist.h @@ -0,0 +1,93 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file DiscreteDist.h + + \author Ralf Gerstenberger + + \date created at 2003/05/09 + + \brief Declaration of odemx::random::DiscreteDist + + \sa DiscreteDist.cpp + + Discrete random number generators + + \since 1.0 +*/ + +#ifndef ODEMX_IDIST_INCLUDED +#define ODEMX_IDIST_INCLUDED + +#include <odemx/random/Dist.h> + +namespace odemx { +namespace random { + +/** + \defgroup idist Integer distributions + \ingroup random + + A group of random number generators which produce integer + random numbers in different distributions. +*/ + +/** \interface DiscreteDist + + \ingroup idist + + \author Ralf Gerstenberger + + \brief Interface for integer distributions + + %DiscreteDist declares the 'int sample()' method for discrete + distribution classes. All derived classes implement this + method to provide the random numbers in different distributions. + + \since 1.0 +*/ +class DiscreteDist +: public Dist +{ +public: + + /** + \brief Construction for user-defined DistContext (i.e. Simulation) + \param title + Label of the generator + \param c + pointer to a DistContext object + */ + DiscreteDist( base::Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~DiscreteDist(); + + /** + \brief Get next random number + + This function returns the next random number. + It is implemented in derived classes which generate + random numbers in different distributions. + */ + virtual int sample() = 0; +}; + +} } // namespace odemx::random + +#endif diff --git a/odemx-lite/include/odemx/random/Dist.h b/odemx-lite/include/odemx/random/Dist.h new file mode 100644 index 0000000000000000000000000000000000000000..a331c452dc7feab1218f99aa7597dde5849eb3db --- /dev/null +++ b/odemx-lite/include/odemx/random/Dist.h @@ -0,0 +1,120 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Dist.h + + \author Ralf Gerstenberger + + \date created at 2003/05/09 + + \brief Declaration of odemx::random::Dist + + \sa Dist.cpp + + \since 1.0 +*/ + +#ifndef ODEMX_DIST_INCLUDED +#define ODEMX_DIST_INCLUDED + +#include <odemx/data/Producer.h> + +namespace odemx { +namespace random { + +class DistContext; + +/** \class Dist + + \ingroup random + + \author Ralf Gerstenberger + + \brief Linear Random Number Generator + + \note LRNG from ODEM + + %Dist is the base class for all random number generators of + ODEMx. It provides an implementation of an integer random + number generator using the linear congruential algorithm. + This algorithm is known to produce sequences of numbers which + are sufficiently random for simulations. \n + This class is not used directly. Instead one of the derived + classes is used, which provide transformations into sequences + of random numbers with different distributions. + + \sa DiscreteDist and ContinuousDist + + \since 1.0 +*/ +class Dist +: public data::Producer +{ +protected: + + /** + \brief Construction + + \param label + Label of the object + */ + Dist( base::Simulation& sim, const data::Label& label = "" ); + /// Destruction + virtual ~Dist(); + +public: + /** + \brief Set seed for the random number generators + \param n + new seed + + The new seed will be used for generating + new random numbers. + + \warning The quality of the generated random numbers + depends on the selected seed! + */ + virtual void setSeed( int n = 0 ); + + /** + \brief Get start seed + + This function returns the start seed of + the random number generator. + */ + unsigned long getSeed(); + +protected: + /** + \brief Get new random number + + This function returns a new random number. It + is used by derived classes. + */ + double getSample(); + +private: + DistContext& context; + unsigned long u; + unsigned long ustart; + unsigned int antithetics; +}; + +} } // namespace odemx::random + +#endif diff --git a/odemx-lite/include/odemx/random/DistContext.h b/odemx-lite/include/odemx/random/DistContext.h new file mode 100644 index 0000000000000000000000000000000000000000..22aacf1a528539e89a196d91f91ce92af5f62fb2 --- /dev/null +++ b/odemx-lite/include/odemx/random/DistContext.h @@ -0,0 +1,121 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file DistContext.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::DistContext + */ + +#ifndef ODEMX_RANDOM_DISTCONTEXT_INCLUDED +#define ODEMX_RANDOM_DISTCONTEXT_INCLUDED + +namespace odemx { +namespace random { + +// forward declaration +class Dist; + +extern const unsigned long zyqmodulo; + +/** \class DistContext + + \ingroup random + + \author Ralf Gerstenberger + + \brief %DistContext stores global data for Dist. + + The random number generator (RNG) Dist does need some 'global' + data for generating independent random numbers. These data are stored + in %DistContext. + + \warning The RNG's in the same DistContext are independent + from one another (within the limits of the RNG in Dist). Those RNG's + in different DistContexts are NOT independent. Without changing the + seed manually one will get the same sequence of random numbers in + every DistContext! + + \since 1.0 +*/ +class DistContext +{ +public: + /** + \brief Construction + */ + DistContext (); + /// Destruction + virtual ~DistContext(); + + /** + \brief Set start seed for new RNG's + \param n + new seed + + The new seed will be used for the initialization + of new RNG's in this context. Choosing a good seed + is not trivial. The one used as default is known + to be sufficient for simulations. + + \warning + The quality of the random numbers + depends on the selected seed! + */ + void setSeed( int n = 0 ); + +protected: + friend class Dist; + + /** + \brief Get current start seed + + This function returns the current seed without + generating a new seed value. The returned value + was used for the last created RNG in this context. + + \sa getNextSeed() + */ + unsigned long getSeed(); + + /** + \brief Get start seed for a new RNG + + This function returns a new seed. The + seed is generated by a random number generator + different from the one used for ordinary random + numbers. That is why the created random number + generators in one %DistContext are independent from + one another. + */ + unsigned long getNextSeed(); + +private: + unsigned long zyqSeed_; + + /** + \brief generate next start seed + */ + void computeNextSeed(); +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_DISTCONTEXT_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/Draw.h b/odemx-lite/include/odemx/random/Draw.h new file mode 100644 index 0000000000000000000000000000000000000000..6495c5906600df829155d5f87cda1a06597857c4 --- /dev/null +++ b/odemx-lite/include/odemx/random/Draw.h @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Draw.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::Draw + */ + +#ifndef ODEMX_RANDOM_DRAW_INCLUDED +#define ODEMX_RANDOM_DRAW_INCLUDED + +#include <odemx/random/DiscreteDist.h> + +namespace odemx { +namespace random { + +/** \class Draw + + \ingroup idist + + \author Ralf Gerstenberger + + \brief Random series of 0 and 1 + + \note Draw from ODEM + + \note supports Report + + Draw provides a random series of 1 and 0. The + probability of the 1 against a 0 is set in the + constructor. + + \since 1.0 +*/ +class Draw +: public DiscreteDist +{ +public: + + /** + \brief Construction for user-defined DistContext (i.e. Simulation) + \param title + Label of the generator + \param c + pointer to DistContext object + \param da + probability of a 1 against a 0 + + The parameter \c da defines the probability + of a 1 against a 0. + */ + Draw( base::Simulation& sim, const data::Label& label, double probability ); + + /// Destruction + virtual ~Draw(); + + /// Get next random number + virtual int sample(); + + /// Get parameter \c da + double getProbability(); + +protected: + double probability_; +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_DRAW_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/Erlang.h b/odemx-lite/include/odemx/random/Erlang.h new file mode 100644 index 0000000000000000000000000000000000000000..6e0974e1dc01047e548150937ef44812d14ca7db --- /dev/null +++ b/odemx-lite/include/odemx/random/Erlang.h @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Erlang.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::Erlang + */ + +#ifndef ODEMX_RANDOM_ERLANG_INCLUDED +#define ODEMX_RANDOM_ERLANG_INCLUDED + +#include <odemx/random/ContinuousDist.h> + +namespace odemx { +namespace random { + +/** \class Erlang + + \ingroup rdist + + \author Ralf Gerstenberger + + \brief %Erlang distribution of random numbers + + \note Erlang from ODEM + + \note supports Report + + Erlang provides a series of Erlang-distributed + random numbers. The parameters are set in the + constructor. + + \since 1.0 +*/ +class Erlang +: public ContinuousDist +{ +public: + + /** + \brief Construction with user-defined DistContext (i.e. Simulation) + \param label + Label of the generator + \param c + Pointer to DistContext object + \param ea rate, the larger, the more spread out the distribution + \param eb shape, affects the shape of the distribution + */ + Erlang( base::Simulation& sim, const data::Label& label, double rate, int shape ); + + /// Destruction + virtual ~Erlang(); + + /// Get next random number + virtual double sample(); + + /// Get parameter a + double getRate(); + /// Get parameter b + int getShape(); + +protected: + double rate_; + int shape_; +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_ERLANG_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/NegativeExponential.h b/odemx-lite/include/odemx/random/NegativeExponential.h new file mode 100644 index 0000000000000000000000000000000000000000..8deaf4f6efddbeecc12d5197ba17e32c9840667c --- /dev/null +++ b/odemx-lite/include/odemx/random/NegativeExponential.h @@ -0,0 +1,83 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file NegativeExponential.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::NegativeExponential + */ + +#ifndef ODEMX_RANDOM_NEGATIVEEXPONENTIAL_INCLUDED +#define ODEMX_RANDOM_NEGATIVEEXPONENTIAL_INCLUDED + +#include <odemx/random/ContinuousDist.h> + +namespace odemx { +namespace random { + +/** \class NegativeExponential + + \ingroup rdist + + \author Ralf Gerstenberger + + \brief Negative exponential distribution of random numbers + + \note NegativeExponential from ODEM + + \note supports Report + + NegativeExponential provides a series of negative exponential + distributed random numbers. + + \since 1.0 +*/ +class NegativeExponential +: public ContinuousDist +{ +public: + + /** + \brief Construction with user-defined DistContext (i.e. Simulation) + \param label + Label of the generator + \param c + pointer to DistContext object + \param na + inverse mean (expected) value, meaning <tt>1 / na</tt> will be used + */ + NegativeExponential( base::Simulation& sim, const data::Label& label, double inverseMean ); + + /// Destruction + virtual ~NegativeExponential(); + + /// Get next random number + virtual double sample(); + + /// Get parameter \c na + double getInverseMean(); + +protected: + double inverseMean_; +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_NEGATIVEEXPONENTIAL_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/Normal.h b/odemx-lite/include/odemx/random/Normal.h new file mode 100644 index 0000000000000000000000000000000000000000..7986c0affe49ec84a757f61bb1817ea5b34a614e --- /dev/null +++ b/odemx-lite/include/odemx/random/Normal.h @@ -0,0 +1,99 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Normal.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::Normal + */ + +#ifndef ODEMX_RANDOM_NORMAL_INCLUDED +#define ODEMX_RANDOM_NORMAL_INCLUDED + +#include <odemx/random/ContinuousDist.h> + +namespace odemx { +namespace random { + +/** \class Normal + + \ingroup rdist + + \author Ralf Gerstenberger + + \brief %Normal distribution of random numbers + + \note Normal from ODEM + + \note supports Report + + Normal provides a series of normal ('Gauss') + distributed random numbers. The parameter mean + and deviation are set in the constructor. + + \since 1.0 +*/ +class Normal +: public ContinuousDist +{ +public: + + /** + \brief Construction with user-defined DistContext (i.e. Simulation) + \param label + Label of the generator + \param c + pointer to DistContext object + \param na + a mean-value + \param nb + b deviation + + The parameter \c na and \c nb define the mean-value + and the deviation of the normal distribution generated + by %Normal. + */ + Normal( base::Simulation& sim, const data::Label& label, double mean, + double deviation ); + + /// Destruction + virtual ~Normal(); + + /// Get next random number + virtual double sample(); + + /// Get parameter na + double getMean(); + /// Get parameter nb + double getDeviation(); + +private: + double zyqu; + double zyqv; + bool zyqeven; + +protected: + double mean_; + double deviation_; +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_NORMAL_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/Poisson.h b/odemx-lite/include/odemx/random/Poisson.h new file mode 100644 index 0000000000000000000000000000000000000000..f1e3d28aaea41d12f2f4deb4338d86ae150aa211 --- /dev/null +++ b/odemx-lite/include/odemx/random/Poisson.h @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Poisson.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::Poisson + */ + +#ifndef ODEMX_RANDOM_POISSON_INCLUDED +#define ODEMX_RANDOM_POISSON_INCLUDED + +#include <odemx/random/DiscreteDist.h> + +namespace odemx { +namespace random { + +/** \class Poisson + + \ingroup idist + + \author Ralf Gerstenberger + + \brief %Poisson distributed discrete random numbers + + \note Poisson from ODEM + + \note supports Report + + Poisson provides a series of Poisson-distributed + discrete random numbers. The parameter \c pa + divergence is set in the constructor. + + \since 1.0 +*/ +class Poisson +: public DiscreteDist +{ +public: + + /** + \brief Construction for user-defined DistContext (i.e. Simulation) + \param title + Label of the generator + \param c + pointer to DistContext object + \param pa + mean value + + The parameter pa defines the mean value + of the Poisson-distribution generated by + this random number generator. + */ + Poisson( base::Simulation& sim, const data::Label& label, double mean ); + + /// Destruction + virtual ~Poisson(); + + /// Get next random number + virtual int sample(); + + /// Get parameter pa + double getMean(); + +protected: + double mean_; +}; + +} } // namespace odemx::random + + +#endif /* ODEMX_RANDOM_POISSON_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/RandomInt.h b/odemx-lite/include/odemx/random/RandomInt.h new file mode 100644 index 0000000000000000000000000000000000000000..8ee129ab94e3e5171414b5f84d8b8739f736d0cf --- /dev/null +++ b/odemx-lite/include/odemx/random/RandomInt.h @@ -0,0 +1,96 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file RandomInt.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::RandomInt + */ + +#ifndef ODEMX_RANDOM_RANDOMINT_INCLUDED +#define ODEMX_RANDOM_RANDOMINT_INCLUDED + +#include <odemx/random/DiscreteDist.h> + +namespace odemx { +namespace random { + +/** \class RandomInt + + \ingroup idist + + \author Ralf Gerstenberger + + \brief %Uniform distributed discrete random numbers + + \note RandomInt from ODEM + + \note supports Report + + RandomInt provides a series of uniformly distributed + integer random numbers in the interval [a, b). The + parameters a and b are set in the constructor. + + \since 1.0 +*/ +class RandomInt +: public DiscreteDist +{ +public: + + /** + \brief Construction for user-defined DistContext (i.e. Simulation) + \param title + Label of the generator + \param c + pointer to DistContext object + \param ra + lower bound - a + \param rb + upper bound - b + + The parameters a and b define the interval [a, b) + of the uniformly distributed random numbers generated + by %RandomInt. + */ + RandomInt( base::Simulation& sim, const data::Label& label, int lowerBound, int upperBound ); + + // Destruction + virtual ~RandomInt(); + + /// Get next random number + virtual int sample(); + + /// Get parameter a + int getLowerBound(); + /// Get parameter b + int getUpperBound(); + +protected: + int lowerBound_; + int upperBound_; + +private: + double zyqSpan_; +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_RANDOMINT_INCLUDED */ diff --git a/odemx-lite/include/odemx/random/Uniform.h b/odemx-lite/include/odemx/random/Uniform.h new file mode 100644 index 0000000000000000000000000000000000000000..bcd41a100d5a0aa676f30700aeeb691a52c2c15e --- /dev/null +++ b/odemx-lite/include/odemx/random/Uniform.h @@ -0,0 +1,96 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Uniform.h + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Declaration of odemx::random::Uniform + */ + +#ifndef ODEMX_RANDOM_UNIFORM_INCLUDED +#define ODEMX_RANDOM_UNIFORM_INCLUDED + +#include <odemx/random/ContinuousDist.h> + +namespace odemx { +namespace random { + +/** \class Uniform + + \ingroup rdist + + \author Ralf Gerstenberger + + \brief %Uniform distribution of random numbers + + \note Uniform from ODEM + + \note supports Report + + Uniform provides a series of uniform + distributed random numbers in the interval [a, b). + The parameters a and b are set in the constructor. + + \since 1.0 +*/ +class Uniform +: public ContinuousDist +{ +public: + + /** + \brief Construction with user-defined DistContext (i.e. Simulation) + \param label + Label of the generator + \param c + pointer to DistContext object + \param ua + lower bound a + \param ub + upper bound b + + The parameters \c ua and \c ub define the interval + of the distribution. + */ + Uniform( base::Simulation& sim, const data::Label& label, double lowerBound, + double upperBound ); + + /// Destruction + virtual ~Uniform(); + + /// Get next random number + virtual double sample(); + + /// Get parameter a + double getLowerBound(); + /// Get parameter b + double getUpperBound(); + +private: + double zyqSpan_; + +protected: + double lowerBound_; + double upperBound_; +}; + +} } // namespace odemx::random + +#endif /* ODEMX_RANDOM_UNIFORM_INCLUDED */ diff --git a/odemx-lite/include/odemx/setup.h b/odemx-lite/include/odemx/setup.h new file mode 100644 index 0000000000000000000000000000000000000000..1973cffdcce16e8817db9448d7adbfe7f6863701 --- /dev/null +++ b/odemx-lite/include/odemx/setup.h @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file odemx/setup.h + * @author Ronald Kluth + * @date created at 2009/08/02 + * @brief Contains preprocessor definitions controlling ODEMx build settings + * @since 3.0 + */ + +#ifndef ODEMX_SETUP_INCLUDED +#define ODEMX_SETUP_INCLUDED + +// NOTE: All defines in this file are guarded with #ifndef in order to avoid +// multiple definitions of the same macro. This can happen if the macro is +// given via compiler command line switch, for example. + +/** + * @name Build Parameters + * @brief Default build parameters for ODEMx and dependent projects + * @{ + */ + +/** + * @def ODEMX_USE_CONTINUOUS + * @brief Enables continuous processes and influences the type of SimTime + * + * The default type used for ODEMx @c SimTime is <tt>long long</tt>. However, + * continuous processes require floating point precision. Therefore, enabling + * this feature will switch the type used for @c SimTime to @c double. + */ +#ifndef ODEMX_USE_CONTINUOUS +#define ODEMX_USE_CONTINUOUS +#endif + +/** + * @def ODEMX_USE_TRACE + * @brief Enables internal state logging of ODEMx classes + * + * This define allows users to get detailed logging information about all state + * changes occurring within ODEMx classes. This can significantly ease the + * debugging of simulation models. As soon as the simulator is working properly, + * the logging output can be reduced to show only experiment-related data by + * disabling internal traces. This also reduces runtime overhead. + */ +#ifndef ODEMX_USE_TRACE +//#define ODEMX_USE_TRACE +#endif + +/** + * @def ODEMX_USE_OBSERVATION + * @brief Enables the observation feature of ODEMx + * + * Observation is an object-object relation with one object taking the role of + * the observable and another taking the role of the observer. An observable + * can inform multiple registered observers of its state changes. This define + * mainly reduces runtime overhead when the feature is not needed. + */ +#ifndef ODEMX_USE_OBSERVATION +//#define ODEMX_USE_OBSERVATION +#endif + +/** + * @def ODEMX_USE_ODBC + * @brief Enables logging to external databases via ODBC + * + * ODEMx has the capability to write log records to databases. The default + * setup enables the use of SQLite database files. This define + * enables the use of external databases by using an ODBC connector. However, + * compiling ODEMx with this option requires ODBC development headers to be + * installed on the host system. + */ +#ifndef ODEMX_USE_ODBC +//#define ODEMX_USE_ODBC +#endif + +#ifndef ODEMX_USE_MACRO_COUNTER +//#define ODEMX_USE_MACRO_COUNTER +#endif +//@} + +//------------------------------------------------------------------dependencies + +// Continuous requires observation because ContuTrace is an observer type +#ifdef ODEMX_USE_CONTINUOUS + #ifndef ODEMX_USE_OBSERVATION + #define ODEMX_USE_OBSERVATION + #endif +#endif /* ODEMX_USE_CONTINUOUS */ + +// Tracing checks the boolean value of ODEMX_TRACE_ENABLED in a condition +#ifdef ODEMX_USE_TRACE + #define ODEMX_TRACE_ENABLED true +#else + #define ODEMX_TRACE_ENABLED false +#endif /* ODEMX_USE_TRACE */ + +#endif /* ODEMX_SETUP_INCLUDED */ diff --git a/odemx-lite/include/odemx/statistics/Accumulate.h b/odemx-lite/include/odemx/statistics/Accumulate.h new file mode 100644 index 0000000000000000000000000000000000000000..11221e9fc4a7f51980fdfc68d5f8d8d4ae5d3dd4 --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Accumulate.h @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Accumulate.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Accumulate + * @sa Accumulate.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_ACCUMULATE_INCLUDED +#define ODEMX_STATS_ACCUMULATE_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/statistics/Tab.h> + +namespace odemx { +namespace statistics { + +/** \class Accumulate + + \ingroup statistics + + \author Ralf Gerstenberger + + \brief Compute statistics about provided data + + Accum computes minimum, maximum, mean-value, + standard deviation and number of samples (size) according to + the simulation time (see Tally). + + Time weighted mean values are computed according to two + different approximation stategies: + + \c Accum::stepwise: assumes constant values between samples + + A value of 1 held for 4 time units, followed by a + value of 0 for 1 time unit will result in a mean + value of (1*4 + 0*1)/5 = 0.8 . + + \c Accum::linear: assumes linear increase/decrease of values + between samples + + A value of 1 held for 4 time units, followed by a + value of 0 for 1 time unit will result in a mean + value of (1*4/2 + 0*1)/5 = 0.4 . + + \note The approximation strategy can be set with the second constructor + parameter, which by default is set to \c stepwise. + + \since 1.0 +*/ +class Accumulate +: public Tab +{ +public: + /// Approximation strategy + enum Approx + { + stepwise, + linear + }; + + /// Construction + Accumulate( base::Simulation& sim, const data::Label& label, Approx app = stepwise ); + /// Destruction + virtual ~Accumulate(); + + /// Update statistics (considering time) + virtual void update( base::SimTime time, double value ); + /// Reset statistics + virtual void reset( base::SimTime time ); + /// Get a count of zero-updates + std::size_t getZeros() const; + /// Get minimum + double getMin() const; + /// Get maximum + double getMax() const; + /// Get average + double getMean() const; + /// Get average (considering time) + double getWeightedMean() const; + /// Get deviation + double getStandardDeviation() const; + /// Get deviation (considering time) + double getWeightedStandardDeviation() const; + /// Implementation of ReportProducer interface + virtual void report( data::Report& report ); +protected: + Approx approximation_; + base::SimTime startTime_; + base::SimTime lastTime_; + double lastValue_; + std::size_t zeros_; + double minValue_; + double maxValue_; + double sum_; + double sumSq_; + double sumWeight_; + double sumSqWeight_; +}; + +} } // namespace odemx::statistics + +#endif /* ODEMX_STATS_ACCUMULATE_INCLUDED */ diff --git a/odemx-lite/include/odemx/statistics/Count.h b/odemx-lite/include/odemx/statistics/Count.h new file mode 100644 index 0000000000000000000000000000000000000000..22e5d97d2076e94e9b45a30e57ab59b6ebfebd22 --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Count.h @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Count.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Count + * @sa Count.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_COUNT_INCLUDED +#define ODEMX_STATS_COUNT_INCLUDED + +#include <odemx/statistics/Tab.h> + +namespace odemx { +namespace statistics { + +/** \class Count + + \ingroup statistics + + \author Ralf Gerstenberger + + \brief Counter + + Count is counting integers. It can be used also to + calculate an integer sum of all provided numbers. + To increase the counter use update(). + + \since 1.0 +*/ +class Count +: public Tab +{ +public: + /// Construction with user-defined simulation context + Count( base::Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~Count(); + + /// Update counter + void update( int value = 1 ); + /// Reset counter and statistics + virtual void reset( base::SimTime time ); + /// Get current counter value + int getValue() const; + /// Implementation of Reporter interface + virtual void report( data::Report& report ); + +private: + /// The counter value + int count_; +}; + +} } // namespace odemx::statistics + +#endif /* ODEMX_STATS_COUNT_INCLUDED */ diff --git a/odemx-lite/include/odemx/statistics/Histogram.h b/odemx-lite/include/odemx/statistics/Histogram.h new file mode 100644 index 0000000000000000000000000000000000000000..b6d7bffe05d4ca024b21b4e468948a802841a3c3 --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Histogram.h @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Histogram.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Histogram + * @sa Histogram.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_HISTOGRAM_INCLUDED +#define ODEMX_STATS_HISTOGRAM_INCLUDED + +#include <odemx/statistics/Tally.h> + +#include <vector> + +namespace odemx { +namespace statistics { + +/** \class Histogram + + \ingroup statistics + + \author Ronald Kluth + + \brief Statistical analysis plus histogram + + Histogram computes a statistical analysis like Tally + and also generates histogram data. + + \since 1.0 +*/ +class Histogram +: public Tally +{ +public: + + struct Cell + { + Cell(): count( 0 ), lowerBound( 0 ), upperBound( 0 ), percentage( 0 ) {} + + std::size_t count; + double lowerBound; + double upperBound; + double percentage; + }; + + typedef std::vector< Cell > CellVec; + + /// Construction with user-defined simulation context + Histogram( base::Simulation& sim, const data::Label& label, + double lowerBound, double upperBound, unsigned int cellCount ); + /// Destruction + virtual ~Histogram(); + + /// Update statistics + virtual void update( double value ); + /// Reset statistics + virtual void reset( base::SimTime time ); + /// Get histogram data + const CellVec& getData(); + /// Implementation of Reporter interface + virtual void report( data::Report& report ); + +private: + /// The lower bound for histogram values + double lowerBound_; + /// The upper bound for histogram values + double upperBound_; + /// The number of categories for values + unsigned int cellCount_; + /// The interval width of one value category + double cellWidth_; + /// The maximum index of the data vector + int maxCellIndex_; + /// The data vector + CellVec cellData_; +}; + +} } // namespace odemx::statistics + +#endif /* ODEMX_STATS_HISTOGRAM_INCLUDED */ diff --git a/odemx-lite/include/odemx/statistics/Regression.h b/odemx-lite/include/odemx/statistics/Regression.h new file mode 100644 index 0000000000000000000000000000000000000000..cf7ad0b2f98077923b4f2b38cf392f6fdd3218b7 --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Regression.h @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Regression.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Regression + * @sa Regression.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_REGRESSION_INCLUDED +#define ODEMX_STATS_REGRESSION_INCLUDED + +#include <odemx/statistics/Tab.h> + +#include <vector> + +namespace odemx { +namespace statistics { + +/** \class Regression + + \ingroup statistics + + \author Ralf Gerstenberger + + \brief %Regression analysis + + \note Regression from ODEM + \note Regression supports Report + + Regression computes the linear correlation between + provided data X and Y by computing two mean values, + whose intersection is the center of rotation, and a slope. + + \since 1.0 +*/ +class Regression +: public Tab +{ +public: + /// Construction with user-defined simulation context + Regression( base::Simulation& sim, const data::Label& label ); + /// Destruction + virtual ~Regression(); + + /// Update statistics + void update( double valueX, double valueY ); + /// Reset statistics + virtual void reset( base::SimTime time ); + /// Check if sufficient data for a regression analysis has been accumulated + bool hasSufficientData() const; + /// get mean of x update values + double getXMean() const; + /// get mean of y update values + double getYMean() const; + /// + double getDx() const; + double getDy() const; + + /** + * @brief Get standard deviation of all residuals + * + * @note Residuals describe the distance of the measured value from + * the estimated linear regression function. + */ + double getResidualStandardDeviation() const; + + /** + * @brief Get the regression coefficient + * + * @note The regression coefficient describes the slope of the linear + * regression function. + */ + double getEstimatedRegressionCoefficient() const; + + /// intercept helper value ??? + double getIntercept() const; + + /** + * @brief Get standard deviation of the regression coefficient estimates + */ + double getRegressionCoefficientStandardDeviation() const; + + /** + * @brief Get the correlation coefficient + * + * The correlation coefficient is a measure for the relationship of + * x and y. \c 0 means no linear correlation exists, while \c 1 means + * there is a strong linear correlation between these variables. + */ + double getCorrelationCoefficient() const; + /// Implementation of Reporter interface + virtual void report( data::Report& report ); + +protected: + double sumX_; + double sumY_; + double sumSqX_; + double sumXMulY_; + double sumSqY_; +}; + +} } // namespace odemx::statistics + +#endif /* ODEMX_STATS_REGRESSION_INCLUDED */ diff --git a/odemx-lite/include/odemx/statistics/Sum.h b/odemx-lite/include/odemx/statistics/Sum.h new file mode 100644 index 0000000000000000000000000000000000000000..e907825a3b7c07270d711fbf70642dd6a8d5ebe6 --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Sum.h @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Sum.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Sum + * @sa Sum.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_SUM_INCLUDED +#define ODEMX_STATS_SUM_INCLUDED + +#include <odemx/statistics/Tab.h> + +namespace odemx { +namespace statistics { + +/** \class Sum + + \ingroup statistics + + \author Ralf Gerstenberger + + \brief Sum + + Sum is used to compute 'double' sums. Use update() + to change the sum. + + \since 1.0 +*/ +class Sum +: public Tab +{ +public: + /// Construction with user-defined simulation context + Sum( base::Simulation& sim, const data::Label& label ); + /// Destruction + virtual ~Sum(); + + /// Update sum + void update( double value = 1.0 ); + /// Reset sum and statistics + virtual void reset( base::SimTime time ); + /// Get current value + double getValue() const; + /// Implementation of Reporter interface + virtual void report( data::Report& report ); + +private: + /// The computed sum + double sum_; +}; + +} } // namespace odemx::statistics + +#endif /* ODEMX_STATS_SUM_INCLUDED */ diff --git a/odemx-lite/include/odemx/statistics/Tab.h b/odemx-lite/include/odemx/statistics/Tab.h new file mode 100644 index 0000000000000000000000000000000000000000..37414528ca762f5fa561d8c69bc09b11f04c2c2d --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Tab.h @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Tab.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Tab + * @sa Tab.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_TAB_INCLUDED +#define ODEMX_STATS_TAB_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/data/ReportProducer.h> + +#include <cstddef> // size_t + +namespace odemx { +namespace statistics { + +/** \class Tab + + \ingroup statistics + + \author Ralf Gerstenberger + + \brief The base for statistics-computing classes. + + \since 1.0 +*/ +class Tab +: public data::ReportProducer +{ +public: + /// Construction with user-defined simulation context + Tab( base::Simulation& sim, const data::Label& label ); + /// Destruction + virtual ~Tab(); + + /// Update usage counter + void update(); + /// Reset usage counter and store reset time + virtual void reset( base::SimTime time ); + /// Get usage counter + std::size_t getUpdateCount() const; + /// Get last reset time + base::SimTime getResetTime() const; + +protected: + /// The usage counter + std::size_t updateCount_; + /// The last reset time + base::SimTime resetTime_; +}; + +} } // namespace odemx::statistics + +#endif /*ODEMX_TAB_INCLUDED*/ diff --git a/odemx-lite/include/odemx/statistics/Tally.h b/odemx-lite/include/odemx/statistics/Tally.h new file mode 100644 index 0000000000000000000000000000000000000000..8d72c09dad8960bcd3d0a92260cd8b8bcb875f87 --- /dev/null +++ b/odemx-lite/include/odemx/statistics/Tally.h @@ -0,0 +1,92 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Tally.h + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Declaration of odemx::statistics::Tally + * @sa Tally.cpp + * @since 3.0 + */ + +#ifndef ODEMX_STATS_TALLY_INCLUDED +#define ODEMX_STATS_TALLY_INCLUDED + +#include <odemx/statistics/Tab.h> + +namespace odemx { +namespace statistics { + +/** \class Tally + + \ingroup statistics + + \author Ralf Gerstenberger + + \brief Compute statistics about provided data + + Tally computes minimum, maximum, mean-value, + standard deviation and number of samples (size) + independent from simulation time (see Accum). + + The average value is computed as follows: + A value of 1 for 4 time units together with a value + of 0 for 1 time unit will result in a mean value of + (1+0)/2 = 0.5. + + \since 1.0 +*/ +class Tally +: public Tab +{ +public: + /// Construction with user-defined simulation context + Tally( base::Simulation& sim, const data::Label& label ); + /// Destruction + virtual ~Tally(); + + /// Update statistics + virtual void update( double value ); + /// Reset statistics + virtual void reset( base::SimTime time ); + /// Get minimum + double getMin() const; + /// Get maximum + double getMax() const; + /// Get average + double getMean() const; + /// Get standard deviation + double getStandardDeviation() const; + /// Implementation of Reporter interface + virtual void report( data::Report& report ); + +protected: + /// The minimum of all update values + double minValue_; + /// The maximum of all update values + double maxValue_; + /// The sum of all update values since last reset + double sum_; + /// The sum of the squares of all update values since last reset + double sumSq_; +}; + +} } // namespace odemx::statistics + +#endif /* ODEMX_STATS_TALLY_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/Bin.h b/odemx-lite/include/odemx/synchronization/Bin.h new file mode 100644 index 0000000000000000000000000000000000000000..d8cc40d44d6a3de7b0bbfe5e19fb3b5a0c675d9b --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Bin.h @@ -0,0 +1,178 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Bin.h + + \author Ralf Gerstenberger + + \date created at 2002/03/26 + + \brief Declaration of odemx::synchronization::Bin and observer + + \sa Bin.cpp + + \since 1.0 +*/ + +#ifndef ODEMX_BIN_INCLUDED +#define ODEMX_BIN_INCLUDED + +#include <odemx/base/SimTime.h> +#include <odemx/data/Producer.h> +#include <odemx/synchronization/Queue.h> +#include <odemx/data/Observable.h> + +namespace odemx { + +// forward declarations +namespace base { +class Process; +class Simulation; +} + +namespace synchronization { + +class BinObserver; + +/** \class Bin + + \ingroup synch + + \author Ralf Gerstenberger + + \brief %Bin is a single bounded (number of token greater or + equal to zero) token abstract resource. + + \note Bin supports Observation + \note Bin supports Trace + \note Bin supports Report + + Bin is a low bounded (token number >= 0) token abstract resource + for synchronising Process objects. A process is blocked in take() + if the requested number of token is greater than the available + number of token. It is reactivated when enough token are given (back) + to the resource. If multiple processes are waiting for reactivation + process-priority and FIFO-strategy are used to choose the process. + Bin is generally used for producer and consumer synchronisation. + + \since 1.0 +*/ +class Bin +: public data::Producer +, public data::Observable< BinObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label for this object + \param startTokenNumber + initial number of token in Bin + \param o + initial observer + */ + Bin( base::Simulation& sim, const data::Label& label, std::size_t initialTokens, + BinObserver* obs = 0 ); + + /// Destruction + ~Bin(); + + /** + \name Token management + + @{ + */ + /** + \brief Take \p n token + + Takes \p n token from resource if possible. Otherwise + the current process is blocked until enough token are + available. If a blocked process is interrupted it is + reactivated and the function returns 0. Without interruption + take returns \p n. + */ + std::size_t take( std::size_t n ); + + /** + \brief Give \p n token + + Gives \p n token to resource. Blocked process objects + could be activated by this call. + */ + void give( std::size_t n ); + + /// Number of tokens available + std::size_t getTokenNumber() const; + //@} + + /// Get list of blocked processes + const base::ProcessList& getWaitingProcesses() const; + +private: + /// available number of tokens + std::size_t tokens_; + /// process management + Queue takeQueue_; + + /// Helper for quick access to the current simulation time + base::SimTime getTime() const; + /// Helper for quick access to the currently running object + base::Sched* getCurrentSched(); + /// Helper for quick access to the current process + base::Process* getCurrentProcess(); + /// Get the label of the current context (process or simulation) + const data::Label& getPartner(); +}; + +/** \interface BinObserver + + \author Ralf Gerstenberger + + \brief Observer for Bin-specific events. + + \sa Bin + + \since 1.0 +*/ +class BinObserver +{ +public: + virtual ~BinObserver() {} + + /// Observe construction + virtual void onCreate( Bin* sender ) {} + + /// Observe failed attempt to take @c n tokens + virtual void onTakeFail( Bin* sender, std::size_t n ) {} + /// Observe successful attempt to take @c n tokens + virtual void onTakeSucceed( Bin* sender, std::size_t n ) {} + /// Observe return of @c n tokens + virtual void onGive( Bin* sender, std::size_t n ) {} + + /// Observe change of the number of tokens + virtual void onChangeTokenNumber( Bin* sender, std::size_t oldTokenNumber, + std::size_t newTokenNumber ) {} +}; + +} } // namespace odemx::synchronization + +#endif + diff --git a/odemx-lite/include/odemx/synchronization/BinT.h b/odemx-lite/include/odemx/synchronization/BinT.h new file mode 100644 index 0000000000000000000000000000000000000000..efe78dc8cc6ec74a414ff21debb647d30738bb18 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/BinT.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file BinT.h + * @author Ronald Kluth + * @date created at 2008/02/17 + * @brief Forwarding header for inclusion of odemx::synchronization::BinT and observer + * @since 2.1 + */ + +#ifndef ODEMX_SYNC_BIN_TEMPLATE_INCLUDED +#define ODEMX_SYNC_BIN_TEMPLATE_INCLUDED + +// no namespaces here, the implementation is declared inside odemx::synchronization + +// template BinT header with implementation +#include <odemx/synchronization/bin/BinTImpl.h> +#include <odemx/synchronization/bin/BinTImpl.cpp> + +#endif /* ODEMX_SYNC_BIN_TEMPLATE_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/CondQ.h b/odemx-lite/include/odemx/synchronization/CondQ.h new file mode 100644 index 0000000000000000000000000000000000000000..6c53e78ddbe58b24358b554635b9c05b61b51f1b --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/CondQ.h @@ -0,0 +1,149 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file CondQ.h + + \author Ralf Gerstenberger + + \date created at 2002/07/11 + + \brief Declaration of odemx::synchronization::CondQ and observer + + \sa CondQ.cpp + + \since 1.0 +*/ + +#ifndef ODEMX_CONDQ_INCLUDED +#define ODEMX_CONDQ_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/synchronization/Queue.h> +#include <odemx/data/Observable.h> + +namespace odemx { + +// forward declarations +namespace base { +class Process; +class Sched; +} + +namespace synchronization { + +class CondQObserver; + +/** \class CondQ + + \ingroup synch + + \author Ralf Gerstenberger + + \brief %CondQ can be used to make a process wait for an + arbitrary condition. + + \note CondQ supports Observation + \note CondQ supports Trace + \note CondQ supports Report + + \since 1.0 +*/ +class CondQ +: public data::Producer +, public data::Observable< CondQObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + \param o + initial observer + */ + CondQ( base::Simulation& sim, const data::Label& label, CondQObserver* obs = 0 ); + + /// Destruction + ~CondQ(); + + /** + \name Synchronisation + @{ + */ + /** + \brief Wait for cond + + If the supplied condition \p cond is false the current process + is blocked until the condition is true and signal() was called. + If a blocked process is interrupted, it is reactivated and + the function returns false. (An interrupted process has + influence on the queue-statistic but not on user and waiting time + statistics.) + */ + bool wait( base::Condition cond ); + + /// Trigger condition check + void signal(); + //@} + + /// Get a list of blocked process objects + const base::ProcessList& getWaitingProcesses() const; + +private: + /// process management + Queue processes_; + + /// Helper for quick access to the current simulation time + base::SimTime getTime() const; + /// Helper for quick access to the currently running object + base::Sched* getCurrentSched(); + /// Helper for quick access to the current process + base::Process* getCurrentProcess(); +}; + +/** \interface CondQObserver + + \author Ralf Gerstenberger + + \brief Observer for CondQ-specific events + + \sa CondQ + + \since 1.0 +*/ +class CondQObserver +{ +public: + virtual ~CondQObserver() { } + + /// Observe construction + virtual void onCreate( CondQ* sender ) {} + + /// Observe process entering wait phase + virtual void onWait( CondQ* sender, base::Process* process ) {} + /// Observe process continuation + virtual void onContinue( CondQ* sender, base::Process* process ) {} + /// Observe triggering of the condition test + virtual void onSignal( CondQ* sender, base::Process* process ) {} +}; + +} } // namespace odemx::synchronization + +#endif diff --git a/odemx-lite/include/odemx/synchronization/IMemory.h b/odemx-lite/include/odemx/synchronization/IMemory.h new file mode 100644 index 0000000000000000000000000000000000000000..b44a3d319450245dcc2303e4ba06f0b7ecd04781 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/IMemory.h @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file IMemory.h + * @author Ronald Kluth + * @date created at 2009/02/11 + * @brief Declaration of interface odemx::synchronization::IMemory + * @since 3.0 + */ + +#ifndef ODEMX_IMEMORY_INCLUDED +#define ODEMX_IMEMORY_INCLUDED + +#include <vector> + +//-----------------------------------------------------------forward declaration + +namespace odemx { + +namespace base { class Sched; } + +namespace synchronization { + +//------------------------------------------------------------header declaration + +/** + * @interface IMemory + * @brief Interface for process memory objects + * + * This interface declares the methods used for the implementation + * of memory objects. + */ +class IMemory +{ +public: + /** + \brief IMemory types + + %IMemory implementations can be different types of structures. When + a pointer to an %IMemory object is returned, it can be useful to have + a means of distinguishing them simply by asking for their type + using \p getMemoryType(). Currently timers, ports and collision + detection objects are supported by the library. However, users are + encouraged to implement IMemory or derive from Memory and + create a user-defined memory type. + */ + enum Type + { + TIMER, + PORTHEAD, + PORTTAIL, + COLLISION_DETECTION, + CONTROL, + USER_DEFINED + }; + + // implicit Default-Constructor + + /// Destruction + virtual ~IMemory(); + + /// Get the memory type as stated by enum Type + virtual Type getMemoryType() const = 0; + /// Check if a memory object is available, if so, processes get alerted + virtual bool isAvailable() = 0; + /// Wake up the remembered processes + virtual void alert() = 0; + /// Remember a process + virtual bool remember( base::Sched* newObject ) = 0; + /// Forget a process + virtual bool forget( base::Sched* rememberedObject ) = 0; + /// Forget all processes + virtual void eraseMemory() = 0; +}; + +/// Provided for convenience, used with Process::wait +typedef std::vector< IMemory* > IMemoryVector; + +} } // namespace odemx::synchronization + +#endif /*ODEMX_IMEMORY_INCLUDED*/ diff --git a/odemx-lite/include/odemx/synchronization/Memory.h b/odemx-lite/include/odemx/synchronization/Memory.h new file mode 100644 index 0000000000000000000000000000000000000000..56ca39bbc61b8b05b441f5ad5167080a8f6689c4 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Memory.h @@ -0,0 +1,266 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002 - 2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Memory.h + + \author Ronald Kluth + + \date created at 2007/04/04 + + \brief Declaration of odemx::synchronization::Memory and observer + + \sa Memory.cpp + + \since 2.0 +*/ + +#ifndef ODEMX_MEMORY_INCLUDED +#define ODEMX_MEMORY_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/base/TypeDefs.h> +#include <odemx/synchronization/IMemory.h> +#include <odemx/data/Observable.h> + +#include <list> +#include <vector> + +namespace odemx { + +//forward declarations +namespace base { +class Process; +class Sched; +} + +namespace synchronization { + +class MemoryObserver; + +/** \class Memory + + \ingroup synch + + \author Ronald Kluth + + \brief The base class for all structures that need to remember processes + + \sa Process, Timer, PortHead, PortTail, WaitCondition + + %Memory is an abstract base class for all user defined structures + in a model that need to store a list of suspended processes in order to wake + them when a certain event occurs. This can be the case for timers, but also + for structures like buffered communication ports. %Memory offers a + means to notify suspended processes of the availability of a resource and + reschedule them at that point in simulation time when a resource becomes + available or a timeout occurs. The recommended usage with processes is + via their \p wait() function. + + \since 2.0 +*/ +class Memory +: public IMemory // implements the memory interface +, public data::Producer +, public data::Observable< MemoryObserver > +{ +public: + friend class base::Process; + + /// Same type as the STL container's size_type + typedef base::SchedList::size_type SizeType; + + /** + * @brief Construction for user-defined Simulation + * + * @param sim Reference to the simulation context + * @param label The object's label + * @param type Type of the memory object + * @param obs Pointer to the initial observer of the object + */ + Memory( base::Simulation& sim, const data::Label& label, Type type, + MemoryObserver* obs = 0 ); + + /// Destruction + virtual ~Memory(); + + /** + * @name Process interaction + * + * These functions can be used by processes to interact with + * Memory objects. + * @{ + */ + /** + * @brief Remember a new schedulable object + * + * @param newObject Pointer to a schedulable object to be stored in memory + * + * @return @c true when successfully stored, @c false if @c newObject is + * already stored + * + * This function is used to add processes or, more generally, + * schedulable objects to the internal list. + * + * @sa forget() + */ + virtual bool remember( base::Sched* newObject ); + + /** + * @brief Remove a stored schedulable object + * + * @param rememberedObject Pointer to the object to be removed + * + * @return @c true when successfully removed, @c false if @c rememberedObject + * not found in list + * + * This function is used to remove processes or, more generally, + * schedulable objects from the internal list. + * + * @sa remember() + */ + virtual bool forget( base::Sched* rememberedObject ); + + /** + * @brief Check if a certain process is waiting for this memory object. + * + * @return @c true if the process is waiting, @c false otherwise + * + * @sa remember(), forget() + */ + bool processIsWaiting (base::Process& process) const; + + /** + * @brief Clear the internal list + * + * This function is used to remove all processes or, more generally, + * schedulable objects from the internal list. + * + * @sa remember(), forget() + */ + virtual void eraseMemory(); + //@} + + /** + * @name Memory status information + * + * These functions return information about the Memory object. + * @{ + */ + /** + * @brief Check availability of an Memory object + * + * @return @c true if the memory object is available, @c false otherwise + * + * This virtual function should be implemented by all + * subclasses of %Memory. It is used to check the availability + * of a resource before suspending the requesting process. + * + * @note Memory objects may always return false (like the default + * implementation) if they use some other means to alert and reschedule + * processes. + * + * @sa Process::wait(), PortHead, PortTail, Timer, WaitCondition + */ + virtual bool isAvailable(); + + /// Check if this Memory object has waiting processes + bool waiting() const; + + /// Get the number of waiting processes + SizeType countWaiting() const; + + /// Get a reference to the list of waiting objects + const base::SchedList& getWaiting() const; + + /** + * @brief Check the type of this Memory object + * + * The memory type is useful when a Memory pointer is returned + * but, depending on the type of this object, different reactions are + * required in the simulator. For example, it is quite a difference if + * a timer is available becuase it was not or a communication port because + * it contains data. + * + * @sa Process::wait() + */ + virtual Type getMemoryType() const; + //@} + + /// Required implementation, simply calls <tt>alert( this )</tt> + virtual void alert(); + + /** + * @brief Alert and reschedule all stored schedulable objects + * @param caller Pointer to an IMemory object to be passed as process alerter + * + * By default, this function is designed to wake up suspended + * or newly created processes, i.e. reschedule them at the current + * simulation time. In case an IMemory interface is implemented in terms + * a Memory member, it makes sense to pass the owner as alerter in + * order to be able to check against the owner's address instead of the + * member's. + */ + void alert( IMemory* caller ); + + +protected: + /** + * @brief Helper for alert() which tests if object @c s is a sleeping Process + * @return @c true if object @c s can be alerted, @false otherwise + */ + bool checkSchedForAlert( base::Sched* s ); + +private: + /// The object's memo type + Type memoryType_; + /// Storage for pointers to schedulable objects + base::SchedList memoryList_; + + /// Helper to log an alert record with details of the internal memory list + void traceAlert(); +}; + +/** \interface MemoryObserver + + \author Ronald Kluth + + \brief Observer for Memory-specific calls. + + \sa Timer, PortHead, PortTail + + \since 2.0 +*/ +class MemoryObserver +{ +public: + virtual ~MemoryObserver() {} + + /// Observe construction + virtual void onCreate( Memory* sender ) {} + + /// Observe addition of a new object to the memory + virtual void onRemember( Memory* sender, base::Sched* s ) {} + /// Observe removal of a previously stored object from the memory + virtual void onForget( Memory* sender, base::Sched* s ) {} + /// Observe alert of all stored schedulable objects + virtual void onAlert( Memory* sender ) {} +}; + +} } // namespace odemx::synchronization + +#endif /*ODEMX_MEMORY_INCLUDED*/ diff --git a/odemx-lite/include/odemx/synchronization/Port.h b/odemx-lite/include/odemx/synchronization/Port.h new file mode 100644 index 0000000000000000000000000000000000000000..e1a3352c7b6b6db97070278812c7ed23c5790dff --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Port.h @@ -0,0 +1,52 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** + * @file Port.h + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Port forwarding header and declaration of odemx::PortHead, odemx::PortTail + * @see PortImpl.h, PortHeadImpl.h, PortTailImpl.h + * @since 2.0 + */ + +#ifndef ODEMX_SYNC_PORT_INCLUDED +#define ODEMX_SYNC_PORT_INCLUDED + +// include port template headers with implementation +#include <odemx/synchronization/port/PortData.h> +#include <odemx/synchronization/port/PortHeadImpl.h> +#include <odemx/synchronization/port/PortTailImpl.h> + +// type definitions for convenience +namespace odemx { +namespace synchronization { + +/// Default PortHead supporting elements derived from PortData +typedef PortHeadT< PortData* > PortHead; +/// Default PortTail supporting elements derived from PortData +typedef PortTailT< PortData* > PortTail; + +/// Default observer for PortHead +typedef PortHeadTObserver< PortData* > PortHeadObserver; +/// Default observer for PortTail +typedef PortTailTObserver< PortData* > PortTailObserver; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_PORT_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/ProcessQueue.h b/odemx-lite/include/odemx/synchronization/ProcessQueue.h new file mode 100644 index 0000000000000000000000000000000000000000..c556edfc1983fac721c9fd85e1e77348f699f616 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/ProcessQueue.h @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ProcessQueue.h + * @author Ralf Gerstenberger + * @date created at 2002/03/25 + * @brief Declaration of odemx::synchronization::ProcessQueue + * @sa ProcessQueue.cpp + * @since 1.0 + */ + +#ifndef ODEMX_SYNC_PROCESSQUEUE_INCLUDED +#define ODEMX_SYNC_PROCESSQUEUE_INCLUDED + +#include <odemx/base/TypeDefs.h> + +namespace odemx { + +// forward declaration +namespace base { +class Process; +} + +namespace synchronization { + +/** \class ProcessQueue + + \ingroup base + + \author Ralf Gerstenberger + + \brief ProcessQueue is used for process synchronization + + ProcessQueue is a general tool for storing Process objects. It is used + by synchronization objects. Every Process can stay in no more than one + ProcessQueue at a time (provisional). If the queue priority of a + Process in a ProcessQueue is changed, the ProcessQueue is updated. + + \since 1.0 +*/ +class ProcessQueue +{ +public: + typedef base::ProcessList::size_type SizeType; + + /// Constructor + ProcessQueue(); + /// Destructor + virtual ~ProcessQueue(); + + /* \name Queue access and information methods + * @{ + */ + /// check if the queue is empty + bool isEmpty() const; + /// get pointer to the first process in the queue + base::Process* getTop() const; + /// get a reference to the list object representing the queue + const base::ProcessList& getList() const; + /// get the current queue length, i.e. number of stored processes + SizeType getLength() const; + /** + * \brief + * get the queue position of a specific process + * \param p + * Process pointer to be found in queue + * \return + * Position of \p p, or 0 when not found + * \note + * The first queue position is \c 1. \c 0 is reserved for errors. + */ + SizeType getPosition( base::Process* p ) const; + //@} + + /* \name Queue manipulation methods + * @{ + */ + /// remove the first Process from the queue + virtual void popQueue(); + /// remove a specific Process \p p from the queue + virtual void remove( base::Process* p ); + /// add Process \p p to the queue, considering order and priority + virtual void inSort( base::Process* p, bool fifo = true ); + //@} + +protected: + /// list of Process pointers representing the queue + base::ProcessList processes_; + /// size counter for efficiency to avoid calling list::size() + SizeType length_; +}; + +/** + * @brief Awakes, i.e. schedules, all Process objects in queue \p q + */ +extern void awakeAll( ProcessQueue* q ); + +/** + * @brief Awakes, i.e. schedules, the first Process object in queue \p q + */ +extern void awakeFirst( ProcessQueue* q ); + +/** + * @brief Awakes, i.e. schedules, the Process object that comes after \p p in queue \p q + */ +extern void awakeNext( ProcessQueue* q, base::Process* p ); + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_PROCESSQUEUE_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/Queue.h b/odemx-lite/include/odemx/synchronization/Queue.h new file mode 100644 index 0000000000000000000000000000000000000000..51f00fe0c554a1a9b79084529350c7b8f402bbfb --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Queue.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Queue.h + * @author Ralf Gerstenberger + * @date created at 2003/06/28 + * @brief Declaration of odemx::synchronization::Queue + * @sa Queue.cpp + * @since 1.0 + */ + +#ifndef ODEMX_SYNC_QUEUE_INCLUDED +#define ODEMX_SYNC_QUEUE_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/synchronization/ProcessQueue.h> + +namespace odemx { + +// forward declarations +namespace base { +class Simulation; +} + +namespace synchronization { + +/** \class Queue + + \ingroup synch + + \author Ralf Gerstenberger + + \brief Wrapper for ProcessQueue with statistics support + + Queue is a wrapper for ProcessQueue. In addition to the + functions of ProcessQueue it also provides statistics about + the queue usage. + + \sa ProcessQueue + + \since 1.0 +*/ +class Queue +: public data::Producer +, public ProcessQueue +{ +public: + /// Same type as the size_type of the used STL container + typedef ProcessQueue::SizeType SizeType; + + /// Contruction for user-defined Simulation + Queue( base::Simulation& sim, const data::Label& label ); + + /// Destruction + virtual ~Queue(); + + /** + * @name Manipulator methods + * @{ + */ + /// Remove the first process from the queue + virtual void popQueue(); + /// Remove the process @c p from the queue + virtual void remove( base::Process* p ); + /// Insert process @c p into the queue, in fifo (default) or lifo mode + virtual void inSort( base::Process* p, bool fifo = true ); + //@} +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_QUEUE_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/Res.h b/odemx-lite/include/odemx/synchronization/Res.h new file mode 100644 index 0000000000000000000000000000000000000000..f6c7ff2151b8bca6e0b5d1b417e2fc1c25503aad --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Res.h @@ -0,0 +1,202 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Res.h + + \author Ralf Gerstenberger + + \date created at 2002/03/21 + + \brief Declaration of odemx::synchronization::Res and observer + + \sa Res.cpp + + \since 1.0 +*/ + +#ifndef ODEMX_RES_INCLUDED +#define ODEMX_RES_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/synchronization/Queue.h> +#include <odemx/data/Observable.h> + +namespace odemx { +namespace synchronization { + +// forward declaration +class ResObserver; + +/** \class Res + + \ingroup synch + + \author Ralf Gerstenberger + + \brief %Res is a double (n>=0 && n<=max number of token) bounded + token abstract resource. + + \note Res supports Observation + \note Res supports Trace + \note Res supports Report + + \sa ResT, ResTChoice + + Res is a double bounded (n>=0 && n<=max number of token) token abstract + resource for synchronising Process objects. A process is blocked if + it tries to acquire more token than are left. It is reactivated when + enough token are released or acquired. If multiple processes are waiting + for reactivation process-priority and FIFO-strategy are used to + choose the process. + Res is generally used for strong limited resource modelling or producer + consumer synchronisation with limited storage capacity. + + \since 1.0 +*/ +class Res +: public data::Producer +, public data::Observable< ResObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + \param startTokenNumber + initial number of token in Res + \param maxTokenNumber + max number of token in Res + \param o + initial observer + */ + Res( base::Simulation& sim, const data::Label& label, std::size_t initialTokens, + std::size_t maxTokens, ResObserver* obs = 0 ); + + /// Destruction + ~Res(); + + /** + \name Token management + @{ + */ + /** + \brief Acquire \p n token + + If there aren't enough token in Res the current + process is blocked. If a blocked process is interrupted, + it is reactivated and acquire() returns 0. Otherwise the + function returns \p n. + */ + std::size_t acquire( std::size_t n ); + + /** + \brief Release \p n token + + Returns \p n token to resource. If there is not enough + room in this resource left an error message is created. + */ + void release( std::size_t n ); + + + /** + \brief Add token to resource + + Add token to the managed token set. + */ + void control( std::size_t n ); + + /** + \brief Remove \p n token from resource + + Remove token from the managed token set. If there are not enough + token left in the resource, the current process is blocked. When + a blocked process is interrupted, the attempt to take token is + cancelled and the function returns 0. + */ + std::size_t unControl( std::size_t n ); + + /// Current number of token available + std::size_t getTokenNumber() const; + + /// Maximum number of token + std::size_t getTokenLimit() const; + //@} + + /// Get list of blocked processes + const base::ProcessList& getWaitingProcesses() const; + +private: + /// current number of tokens + std::size_t tokens_; + /// max number of tokens + std::size_t tokenLimit_; + /// process management + Queue acquireQueue_; + + /// Helper for quick access to the current simulation time + base::SimTime getTime() const; + /// Helper for quick access to the currently running object + base::Sched* getCurrentSched(); + /// Helper for quick access to the current process + base::Process* getCurrentProcess(); + /// Get the label of the currently active context (process or sim) + const data::Label& getPartner(); +}; + +/** \interface ResObserver + + \author Ralf Gerstenberger + + \brief Observer for Res specific events + + \sa Res + + \since 1.0 +*/ +class ResObserver +{ +public: + virtual ~ResObserver() {} + + /// Observe construction + virtual void onCreate( Res* sender ) {} + + /// Observe blocking of acquire + virtual void onAcquireFail( Res* sender, std::size_t n ) {} + /// Observe successful acquiration of n token + virtual void onAcquireSucceed( Res* sender, std::size_t n ) {} + /// Blocking release of n token + virtual void onReleaseFail( Res* sender, std::size_t n ) {} + /// Successful release of n token + virtual void onReleaseSucceed( Res* sender, std::size_t n ) {} + /// Increased token limit + virtual void onControl( Res* sender, std::size_t n ) {} + /// Decreased toekn limit + virtual void onUnControl( Res* sender, std::size_t n ) {} + /// Change of token number + virtual void onChangeTokenNumber( Res* sender, std::size_t oldTokenNumber, + std::size_t newTokenNumber ) {} +}; + +} } // namespace odemx::synchronization + +#endif + diff --git a/odemx-lite/include/odemx/synchronization/ResT.h b/odemx-lite/include/odemx/synchronization/ResT.h new file mode 100644 index 0000000000000000000000000000000000000000..a3f9194effcaf6f8d128d72d7c82f13c8598dd0d --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/ResT.h @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Bin.h + + \author Ronald Kluth + + \date created at 2008/02/17 + + \brief Forwarding header for inclusion of odemx::ResT, ResTChoice, and observers + + \since 2.1 +*/ + +#ifndef ODEMX_RES_TEMPLATE_INCLUDED +#define ODEMX_RES_TEMPLATE_INCLUDED + +// template ResTBase header with implementation +#include <odemx/synchronization/res/ResTBase.h> +#include <odemx/synchronization/res/ResTBase.cpp> +// template ResT header with implementation +#include <odemx/synchronization/res/ResT.h> +#include <odemx/synchronization/res/ResT.cpp> +// template ResTChoice header with implementation +#include <odemx/synchronization/res/ResTChoice.h> +#include <odemx/synchronization/res/ResTChoice.cpp> + +#endif /* ODEMX_RES_TEMPLATE_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/Timer.h b/odemx-lite/include/odemx/synchronization/Timer.h new file mode 100644 index 0000000000000000000000000000000000000000..a134f9a23589efbedb186ad68cb9819f41dae024 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Timer.h @@ -0,0 +1,277 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Timer.h + + \author Ronald Kluth + + \date created at 2007/04/04 + + \brief Declaration of odemx::synchronization::Timer and observer + + \sa Timer.cpp + + \since 2.0 +*/ + +#ifndef ODEMX_TIMER_INCLUDED +#define ODEMX_TIMER_INCLUDED + +#include <odemx/base/Event.h> +#include <odemx/base/SimTime.h> +#include <odemx/synchronization/Memory.h> + +namespace odemx { + +// forward declarations +namespace base { +class Process; +class Sched; +class Simulation; +} + +namespace synchronization { + +class TimerObserver; + +/// maximum priority +extern const int MAX_PRIORITY; + +/** \class Timer + + \ingroup synch + + \author Ronald Kluth + + \brief %Timers trigger an event to wake up suspended processes in a model. + + \note %Timer supports Observation. + \note %Timer supports Trace. + + \sa Process, Event, Simulation + + %Timer is a class provided for convenience. When processes are suspended + using the \p Process::wait() function, a Timer can be used to wake up + processes if no other Memory object becomes available within a certain + amount of time. Timers should not be used to implement arbitrary events, + instead different kinds of events should be derived from the + base class Event. By default, Timers have maximum priority of all + schedulable objects and as such they will be triggered first when + simulation time reaches their execution time. + + \since 2.0 +*/ + +class Timer +: public base::Event // is a DataProducer +, public IMemory // derive from interface to avoid DataProducer ambiguity +, public data::Observable< TimerObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param sim + pointer to the Simulation object + \param l + label of this object + \param to + initial timer observer + */ + Timer( base::Simulation& sim, const data::Label& label, TimerObserver* obs = 0 ); + + /// Destruction + virtual ~Timer(); + + /** + \name Timer Scheduling + + These functions are used to schedule a timeout event + in simulation time. Timers are kept in the same + schedule as processes and other events and they follow the + same scheduling rules. However, their default priority is + set to maximum. + + @{ + */ + /** + \brief Trigger the timeout at simulation time \p now + \p t + + This function schedules the timer at time \p now + \p t before + all other processes and events at that point in simulation time. + Scheduling a + %Timer at SimTime \p now will not suspend the execution of + the current process . The calling process, however, should suspend + its execution via Process::wait(), which will automatically + register that process with the Memory objects given as parameters. + */ + void setIn( base::SimTime t ); + + /** + \brief Trigger the timeout at absolute simulation time \p t + + This function schedules the timer at the absolute simulation + time \p t before all other processes and events with the same + execution time. + Scheduling a %Timer at SimTime \p now will not suspend the execution of + the current process. The calling process, however, should suspend + its execution via Process::wait(), which will automatically + register that process with the Memory objects given as parameters. + */ + void setAt( base::SimTime t ); + + /** + \brief Reschedule the timeout to simulation time \p now + \p t. + + This function reschedules the timer at time \p now + \p t before + all other processes with the same execution time + */ + void reset( base::SimTime t ); + + /** + \brief Remove the %Timer from the schedule + + This function removes the timer from the execution list + */ + void stop(); + + /** + \brief Check if the %Timer is scheduled for execution + \return + true when listed in schedule + + This function reports whether the time is scheduled or not. + */ + bool isSet(); + //@} + + /** + \brief Register a process to wake with this timer + \return + true if sucessfully added \p p to timer memory + \param p + process to be remembered + + This function stores process \p p in the timer's memory. + All the stored processes are rescheduled when the + timeout is triggered. + + \sa removeProcess() + */ + bool registerProcess( base::Process* p ); + + /** + \brief Remove a registered process from timer's memory + \return + true if sucessfully remove \p p + \param p + process to be removed + + This function removes process \p p from the timer's memory. + + \sa registerProcess() + */ + bool removeProcess( base::Process* p ); + + /// Get a list of the waiting processes + const base::SchedList& getWaiting() const; + +protected: + + /** + \brief Reimplemented from Event, schedules all remembered Processes + + This function alerts all processes in the timer's memory. + These processes are then rescheduled at time \p now. + */ + virtual void eventAction(); + + /** + * @name IMemory implementation + * + * To preserve a single inheritance line of DataProducer, Timer only + * inherits from IMemory and has to implement its functions almost + * identical to Memory. + * @{ + * + * @sa IMemory + */ +public: + /// Get memory type + virtual IMemory::Type getMemoryType() const; + /// Check availability, timers are available when they are not scheduled + virtual bool isAvailable(); + /// Alert all waiting processes after a timeout + virtual void alert(); + +private: +// friend class base::Process; + + /// Store a schedulable object + virtual bool remember( base::Sched* newObject ); + /// Remove a schedulable object from memory + virtual bool forget( base::Sched* rememberedObject ); + /// Erase all schedulable objects from memory + virtual void eraseMemory(); + +private: + /// Internal memory object to which all IMemory-calls are forwarded + Memory memory_; + //@} +}; + +/** \interface TimerObserver + + \author Ronald Kluth + + \brief Observer for Timer-specific calls. + + \sa Timer, Event + + \since 2.0 +*/ +class TimerObserver +: public base::EventObserver +{ +public: + virtual ~TimerObserver() {} + + /// Observe construction +// virtual void onCreate( Timer* sender ) {} + + /// Observe activation with relative time + virtual void onSetIn( Timer* sender, base::SimTime t ) {} + /// Observe activation with absolute time + virtual void onSetAt( Timer* sender, base::SimTime t ) {} + /// Observe timer reset and rescheduling + virtual void onReset( Timer* sender, base::SimTime oldTime, base::SimTime newTime ) {} + /// Observe timer stop + virtual void onStop( Timer* sender ) {} + + /// Observe process registration + virtual void onRegisterProcess( Timer* sender, base::Process* p ) {} + /// Observe process removal + virtual void onRemoveProcess( Timer* sender, base::Process* p ) {} + /// Observe timeout, execution of the timer + virtual void onTimeout( Timer* sender ) {} +}; + +} } // namespace odemx::synchronization + +#endif /*ODEMX_TIMER_INCLUDED*/ + diff --git a/odemx-lite/include/odemx/synchronization/Wait.h b/odemx-lite/include/odemx/synchronization/Wait.h new file mode 100644 index 0000000000000000000000000000000000000000..883eaac02fafb52db6048c354cd9dac13c80e919 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/Wait.h @@ -0,0 +1,211 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Wait.h + + \author Ralf Gerstenberger + + \date created at 2003/06/06 + + \brief Declaration of odemx::synchronization::Wait + + \sa Wait.cpp + + \since 1.0 +*/ + +#ifndef ODEMX_WAIT_INCLUDED +#define ODEMX_WAIT_INCLUDED + +#include <odemx/setup.h> + +#ifdef ODEMX_USE_OBSERVATION + +#include <odemx/base/Process.h> +#include <odemx/data/Producer.h> + +#include <list> + + +namespace odemx { +namespace synchronization { + +/** \class Wait + + \ingroup synch + + \author Ralf Gerstenberger + + \brief %Wait for termination of a number of process objects + + \note Wait supports Trace + @note This class can only be used when ODEMX_USE_OBSERVATION is defined + in odemx/setup.h + + %Wait is used to synchronize a process with the termination of + one ore more partner processes. + + \since 1.0 +*/ +class Wait +: public data::Producer +, public base::ProcessObserver +{ +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + */ + Wait( base::Simulation& sim, const data::Label& label ); + + /** + \brief Construction and wait for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + \param p1 + process to wait for + + This constructor creates a Wait object and waits for + Process \p p1 to finish. If the blocked Process is interrupted, + it is reactivated and the constructor returns. To check whether + the process was interrupted, use the isInterrupted() method of + Process. + */ + Wait( base::Simulation& sim, const data::Label& label, base::Process* p1 ); + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + \param p1 + first process to wait for + \param p2 + second process to wait for + \param all + wait for \p all processes + + This constructor creates a Wait object and waits for the Process + objects \p p1 and (or) \p p2 to finish. If the blocked Process + is interrupted, it is reactivated and the constructor returns. + To check whether the process was interrupted, use the isInterrupted() + method of Process. + */ + Wait( base::Simulation& sim, const data::Label& label, base::Process* p1, + base::Process* p2, bool all = true ); + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + \param p1 + first process to wait for + \param p2 + second process to wait for + \param p3 + third process to wait for + \param all + wait for \p all processes + + This constructor creates a Wait object and waits for the Process + objects \p p1, \p p2 and(or) \p p3 to finish. If the blocked Process + is interrupted, it is reactivated and the constructor returns. + To check whether the process was interrupted, use the isInterrupted() + method of Process. + */ + Wait( base::Simulation& sim, const data::Label& label, base::Process* p1, + base::Process* p2, base::Process* p3, bool all = true ); + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + abel of this object + \param size + number of processes in \p p + \param p + processes to wait for + \param all + wait for \p all processes + + This constructor creates a Wait object and waits for the Process + objects stored in \p p to finish. If the blocked Process + is interrupted, it is reactivated and the constructor returns. + To check whether the process was interrupted, use the isInterrupted() + method of Process. + */ + Wait( base::Simulation& sim, const data::Label& label, int size, base::Process* p[], + bool all = true ); + + /// Destruction + virtual ~Wait(); + + /// Add process \p p to list of observed processes + void addProcess( base::Process* p ); + + /// Remove process \p p from list of observed processes + void removeProcess( base::Process* p ); + + /// Get the list of observed processes + const base::ProcessList& getWaitingProcesses() const; + + /// Get Condition (wait for one or all observed Process objects to finish) + bool getCondition() const; + + /// Set Condition (wait for one or all observed Process objects to finish) + void setCondition( bool all = true ); + + /** + \brief Wait for one / all observed processes to finish + + Wait for one or all observed processes to finish. If the blocked + Process is interrupted it is reactivated and wait() returns false. + Otherwise wait() returns true. + */ + bool wait(); + +public: + // ProcessObserver functions + virtual void onChangeProcessState( base::Process* sender, + base::Process::ProcessState oldState, + base::Process::ProcessState newState ); + +private: + base::Process* waitCaller_; ///< blocked process + base::ProcessList observedProcesses_; ///< observed processes + bool waitForAll_; ///< condition + + void initObservedList( size_t size, base::Process* p[] ); ///< init observed list + bool checkObserved(); ///< check condition +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_USE_OBSERVATION */ + +#endif diff --git a/odemx-lite/include/odemx/synchronization/WaitQ.h b/odemx-lite/include/odemx/synchronization/WaitQ.h new file mode 100644 index 0000000000000000000000000000000000000000..c73224da2312973ff4f0140f47d0a7678a0402ed --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/WaitQ.h @@ -0,0 +1,249 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file WaitQ.h + + \author Ralf Gerstenberger + + \date created at 2002/03/26 + + \brief Declaration of odemx::synchronization::WaitQ and observer + + \sa WaitQ.cpp + + \since 1.0 +*/ + +#ifndef ODEMX_WAITQ_INCLUDED +#define ODEMX_WAITQ_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/synchronization/Queue.h> +#include <odemx/data/Observable.h> + +namespace odemx { + +// forward declarations +namespace base { +class Process; +class Simulation; +} + +namespace synchronization { + +class WaitQObserver; + +/** \class WaitQ + + \ingroup synch + + \author Ralf Gerstenberger + + \brief %WaitQ realises a master slave synchronisation, + where the master gets control after successful synchronisation. + + \note WaitQ supports Observation + \note WaitQ supports Trace + \note WaitQ supports Report + + WaitQ realises a master slave synchronisation scheme. Two processes + are synchronised with each other. One plays the role of a master process + and gets control (execution) after successful synchronisation. The other + (slave) is frozen and returned to the master process. A master process + can provide a selection function to synchronise with particular processes + only. If multiple processes could be used for synchronisation process- + priority and FIFO-strategy are used to choose the process. + WaitQ is used for general process to process synchronisation. + + \since 1.0 +*/ +class WaitQ +: public data::Producer +, public data::Observable< WaitQObserver > +{ +public: + + /** + \brief Construction for user-defined Simulation + \param s + pointer to Simulation object + \param l + label of this object + \param o + initial observer + */ + WaitQ( base::Simulation& sim, const data::Label& label, WaitQObserver* obs = 0 ); + + /// Destruction + ~WaitQ(); + + /** + \name Master-slave synchronisation + @{ + */ + /** + \brief Wait for activation by a 'master' process + + A process calling wait() is deactivated and passed + over to a process synchronising with coopt() or avail(). If + a slave process is interrupted before a successful synchronisation + it is reactivated and the function returns false. (An interrupted + slave process does not change user and waiting time statistics, but has + influence on queue statistics.) + */ + bool wait(); + + /** + \brief Wait for activation by a 'master' process + + A process calling wait() is deactivated and passed + over to a process synchronising with coopt() or avail(). + This overloaded version requires the master's weight function + to properly synchronize a waiting slave with the master for + which the weight function returns the highest value. + If a slave process is interrupted before a successful synchronisation + it is reactivated and the function returns false. (An interrupted + slave process does not change user and waiting time statistics, but has + influence on queue statistics.) + */ + bool wait( base::Weight weightFct ); + + /** + \brief Get a 'slave' process + + A master process uses coopt() to synchronise with a slave process. + The master can provide a 'selection function' to synchronise with + a specific slave process. Until there is a suitable slave process + available the master process is blocked. If a blocked master process + is interrupted the synchronisation attempt is cancelled and coopt() + returns 0. (An interrupted master process does not change user and wait + time statistics, but has influence on queue statistics.) + + \warning A master may not call interrupt() to reactivate a received slave(). + */ + base::Process* coopt( base::Selection sel = 0 ); + + /** + \brief Get a 'slave' process by evaluating a weight function + + A master process uses coopt() to synchronise with a slave process. + The master can also provide a 'weight function' to synchronise with + a specific slave process. If there is no slave process + available the master process is blocked. If a blocked master process + is interrupted the synchronization attempt is cancelled and coopt() + returns 0. (An interrupted master process does not change user and wait + time statistics, but has influence on queue statistics.) + + \warning A master may not call interrupt() to reactivate a received slave(). + */ + base::Process* coopt( base::Weight weightFct ); + + /** + \brief Get available slaves without blocking (optional: select slave) + + A master process can use avail() to get a suitable slave process if + available. Otherwise avail() returns 0. + + \warning A master may not call interrupt() to reactivate a received slave(). + */ + base::Process* avail( base::Selection sel = 0 ); + //@} + + /// List of blocked slaves + const base::ProcessList& getWaitingSlaves() const; + /// List of blocked masters + const base::ProcessList& getWaitingMasters() const; + +private: + /// master management + Queue masterQueue_; + /// slave management + Queue slaveQueue_; + + /// find slave + base::Process* getSlave( base::Process* master = 0, base::Selection sel = 0 ); + /// find slave by weight + base::Process* getWeightedSlave( base::Process* master = 0, base::Weight weightFct = 0 ); + /// statistics + void updateStatistics( base::Process* master, base::Process* slave ); + /// master synch. implementation + base::Process* sync( bool wait, base::Selection sel ); + + /// Helper for quick access to the current simulation time + base::SimTime getTime() const; + /// Helper for quick access to the currently running object + base::Sched* getCurrentSched(); + /// Helper for quick access to the current process + base::Process* getCurrentProcess(); +}; + +/** \interface WaitQObserver + + \author Ralf Gerstenberger + + \brief Observer for WaitQ-specific events + + \sa WaitQ + + \since 1.0 +*/ +class WaitQObserver +{ +public: + virtual ~WaitQObserver() {} + + /// Construction + virtual void onCreate( WaitQ* sender ) {} + + /// Process is synchronising as slave + virtual void onWait( WaitQ* sender, base::Process* slave ) {} + /// Process is synchronising as slave + virtual void onWaitWeight( WaitQ* sender, base::Process* slave ) {} + /// Process is blocked in synchronisation as master + + virtual void onCooptFail( WaitQ* sender, base::Process* master ) {} + /// Process succeeds in synchronisation as master, getting slave + virtual void onCooptSucceed( WaitQ* sender, base::Process* master, + base::Process* slave ) {} + /// master Process doesn't find any slave + virtual void onAvailFail( WaitQ* sender, base::Process* master ) {} + /// master Process find some slave + virtual void onAvailSucceed( WaitQ* sender, base::Process* master, + base::Process* slave ) {} + + /// Process is blocked in synchronisation as master for a particular slave + virtual void onCooptSelFail( WaitQ* sender, base::Process* master ) {} + /// Process succeeds in synchronisation as master, getting a particular slave + virtual void onCooptSelSucceed( WaitQ* sender, base::Process* master, + base::Process* slave ) {} + /// master Process doesn't find a particular slave + virtual void onAvailSelFail( WaitQ* sender, base::Process* master ) {} + /// master Process find a particular slave + virtual void onAvailSelSucceed( WaitQ* sender, base::Process* master, + base::Process* slave ) {} + + /// Process is blocked in synchronisation as master for a particular slave + virtual void onCooptWeightFail( WaitQ* sender, base::Process* master ) {} + /// Process succeeds in synchronisation as master, getting a particular slave + virtual void onCooptWeightSucceed( WaitQ* sender, base::Process* master, + base::Process* slave ) {} +}; + +} } // namespace odemx::synchronization + +#endif diff --git a/odemx-lite/include/odemx/synchronization/bin/BinTImpl.cpp b/odemx-lite/include/odemx/synchronization/bin/BinTImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddd211f071941813d488b60836fcf82dd80817ac --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/bin/BinTImpl.cpp @@ -0,0 +1,259 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file BinTImpl.cpp + * @author Ronald Kluth + * @date created at 2008/02/18 + * @brief Implementation of odemx::sync::BinT + * @sa BinTImpl.h + * @since 2.1 + */ + +#include <odemx/util/TypeToString.h> +#include <odemx/synchronization/bin/BinTImpl.h> +#include <odemx/base/Sched.h> +#include <odemx/base/Process.h> + +#include <iterator> + +namespace odemx { +namespace synchronization { + +template< typename TokenT > +BinT< TokenT >::BinT( base::Simulation& sim, const data::Label& label, + BinTObserver< TokenT >* obs ) +: data::Producer( sim, label ) +, data::Observable< BinTObserver< TokenT > >( obs ) +, tokenStorage_() +, tokenCount_( 0 ) +, takeQueue_( sim, getLabel() + ".queue" ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(BinT< TokenT >) ); + + statistics << param( "queue", takeQueue_.getLabel() ).scope( typeid(BinT< TokenT >) ); + statistics << param( "initial tokens", tokenCount_ ).scope( typeid(BinT< TokenT >) ); + statistics << param( "token type", odemx::typeToString( typeid(TokenT) ) ) + .scope( typeid(BinT< TokenT >) ); + + statistics << update( "tokens", tokenCount_ ).scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_T(BinTObserver< TokenT >, Create(this)); +} + +template < typename TokenT > +BinT< TokenT >::BinT( base::Simulation& sim, const data::Label& label, + typename BinT< TokenT >::TokenVec& initialTokens, + BinTObserver< TokenT >* obs ) +: data::Producer( sim, label ) +, data::Observable< BinTObserver< TokenT > >( obs ) +, tokenStorage_( initialTokens.begin(), initialTokens.end() ) +, tokenCount_( tokenStorage_.size() ) +, takeQueue_( sim, getLabel() + ".queue" ) +{ + ODEMX_TRACE << log( "create and tokens" ).scope( typeid(BinT< TokenT >) ); + + statistics << param( "queue", takeQueue_.getLabel() ).scope( typeid(BinT< TokenT >) ); + statistics << param( "initial tokens", tokenCount_ ).scope( typeid(BinT< TokenT >) ); + statistics << param( "token type", odemx::typeToString( typeid(TokenT) ) ) + .scope( typeid(BinT< TokenT >) ); + + statistics << update( "tokens", tokenCount_ ).scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_T(BinTObserver< TokenT >, Create(this)); +} + +template < typename TokenT > +BinT< TokenT >::~BinT() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(BinT< TokenT >) ); +} + +template < typename TokenT > +std::unique_ptr< typename BinT< TokenT >::TokenVec > +BinT< TokenT >::take( size_t n ) +{ + // resource handling only implemented for processes + if( ! getCurrentSched() + || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "BinT::take(): called by non-Process object" ) + .scope( typeid(BinT< TokenT >) ); + return std::unique_ptr< TokenVec >(nullptr); + } + + base::Process* currentProcess = getCurrentProcess(); + + // compute order of service + takeQueue_.inSort( currentProcess ); + + if( n > tokenCount_ || currentProcess != takeQueue_.getTop() ) + { + ODEMX_TRACE << log( "take failed" ) + .detail( "partner", currentProcess ) + .detail( "requested tokens", n ) + .scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_T(BinTObserver< TokenT >, TakeFail(this, n)); + + // statistics + base::SimTime waitStart = getCurrentTime(); + + // block execution + while( n > tokenCount_ || currentProcess != takeQueue_.getTop() ) + { + currentProcess->sleep(); + + if( currentProcess->isInterrupted() ) + { + takeQueue_.remove( currentProcess ); + return std::unique_ptr< TokenVec >(nullptr); + } + } + // block released here + + // statistics, log the waiting period + base::SimTime waitTime = getCurrentTime() - waitStart; + statistics << update( "wait time", waitTime ).scope( typeid(BinT< TokenT >) ); + } + + // create return vector + std::unique_ptr< typename BinT< TokenT >::TokenVec > tokenReturn( + new typename BinT< TokenT >::TokenVec( + tokenStorage_.begin(), tokenStorage_.begin() + n ) ); + + ODEMX_TRACE << log( "change token number" ).valueChange( tokenCount_, tokenCount_ - n ) + .scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_ATTR_T(BinTObserver< TokenT >, TokenNumber, tokenCount_, tokenCount_ - n); + + // remove tokens from store + tokenStorage_.erase( tokenStorage_.begin(), tokenStorage_.begin() + n ); + tokenCount_ -= n; + + ODEMX_TRACE << log( "take succeeded" ) + .detail( "partner", currentProcess ) + .detail( "requested tokens", n ) + .scope( typeid(BinT< TokenT >) ); + + // statistics + statistics << count( "users" ).scope( typeid(BinT< TokenT >) ); + statistics << update( "tokens", tokenCount_ ).scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_T(BinTObserver< TokenT >, TakeSucceed(this, n)); + + // remove process from list + takeQueue_.remove( currentProcess ); + + // awake next + awakeFirst( &takeQueue_ ); + + // return token + return tokenReturn; +} + +template < typename TokenT > +void BinT< TokenT >::give( const TokenT& token ) +{ + std::vector< TokenT > tmpVec; + tmpVec.push_back( token ); + give( tmpVec ); +} + +template < typename TokenT > +void BinT< TokenT >::give( const typename BinT< TokenT >::TokenVec& tokens ) +{ + if ( tokens.empty() ) + { + error << log( "BinT::give(): vector empty; no tokens provided" ) + .scope( typeid(BinT< TokenT >) ); + return; + } + + std::size_t n = tokens.size(); + + ODEMX_TRACE << log( "change token number" ).valueChange( tokenCount_, tokenCount_ + n ) + .scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_ATTR_T(BinTObserver< TokenT >, TokenNumber, tokenCount_, tokenCount_ + n); + + // transfer token to tokenStore + tokenStorage_.insert( tokenStorage_.end(), tokens.begin(), tokens.end() ); + // set token count + tokenCount_ += n; + + ODEMX_TRACE << log( "give" ) + .detail( "partner", getCurrentProcess() ) + .detail( "given tokens", n ) + .scope( typeid(BinT< TokenT >) ); + + // statistics + statistics << count( "providers" ).scope( typeid(BinT< TokenT >) ); + statistics << update( "tokens", tokenCount_ ).scope( typeid(BinT< TokenT >) ); + + // observer + ODEMX_OBS_T(BinTObserver< TokenT >, Give(this, n)); + + // wake up wating process objects + awakeFirst( &takeQueue_ ); +} + +template < typename TokenT > +std::size_t BinT< TokenT >::getTokenNumber() const +{ + return tokenCount_; +} + +template < typename TokenT > +const typename BinT< TokenT >::StorageType& +BinT< TokenT >::getTokenStore() const +{ + return tokenStorage_; +} + +template < typename TokenT > +const base::ProcessList& BinT< TokenT >::getWaitingProcesses() const +{ + return takeQueue_.getList(); +} + +template < typename TokenT > +base::SimTime BinT< TokenT >::getCurrentTime() const +{ + return getSimulation().getTime(); +} + +template < typename TokenT > +base::Sched* BinT< TokenT >::getCurrentSched() +{ + return getSimulation().getCurrentSched(); +} + +template < typename TokenT > +base::Process* BinT< TokenT >::getCurrentProcess() +{ + return getSimulation().getCurrentProcess(); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/include/odemx/synchronization/bin/BinTImpl.h b/odemx-lite/include/odemx/synchronization/bin/BinTImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..b0882cf959b35dd16467fd7b59dfe5e8e3073637 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/bin/BinTImpl.h @@ -0,0 +1,200 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file BinTImpl.h + * @author Ronald Kluth + * @date created at 2008/02/18 + * @brief Declaration of odemx::synchronization::BinT and observer + * @note Do not include this header directly, + * use odemx/synchronization/BinTemplate.h instead. + * @sa BinTImpl.cpp + * @since 2.1 + */ + +#ifndef ODEMX_SYNC_BINT_IMPL_INCLUDED +#define ODEMX_SYNC_BINT_IMPL_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/synchronization/Queue.h> +#include <odemx/data/Observable.h> + +#include <deque> +#include <memory> +#include <vector> + +namespace odemx { + +// forward declarations +namespace base { +class Process; +class Sched; +class Simulation; +} + +namespace synchronization { + +template < typename TokenT > class BinTObserver; + +/** \class BinT + + \author Ralf Gerstenberger + + \brief BinT is a resource holding objects of type T. + + \note BinT supports Observation + + \note BinT supports Trace + + BinT is a low bounded (token number >= 0) resource for synchronizing + Process objects. A process is blocked in take() if the requested number + of tokens is greater than the available tokens. It is reactivated + when enough tokens are given (back) to the resource. If multiple process + objects are waiting for reactivation process-priority and FIFO-strategy + are used to choose the process. BinT is generally used for producer and + consumer synchronization. + + \since 2.1 +*/ +template < typename TokenT > +class BinT +: public data::Producer +, public data::Observable< BinTObserver< TokenT > > +{ +public: + + typedef TokenT TokenType; + typedef std::vector< TokenType > TokenVec; + typedef std::deque< TokenType > StorageType; + typedef BinTObserver< TokenType > ObserverType; + + /** + \brief Construction for user-defined Simulation, no initial tokens + \param s + pointer to simulation + \param l + label of BinT object + \param o + observer of BinT object + */ + BinT( base::Simulation& sim, const data::Label& label, ObserverType* obs = 0 ); + + /** + \brief Construction for user-defined Simulation + \param s + pointer to simulation + \param l + label of BinT object + \param o + observer of BinT object + */ + BinT( base::Simulation& sim, const data::Label& label, TokenVec& initialTokens, + ObserverType* obs = 0 ); + + /// Destruction + virtual ~BinT(); + + /** + \name Token management + + @{ + */ + /** + \brief take \p n tokens + + Takes n tokens from BinT if possible. Otherwise, the + current process is blocked until enough tokens become + available. + + \note The returned vector is dynamically allocated with \c new, + which means that the caller has to call delete on it. + */ + std::unique_ptr< TokenVec > take( std::size_t n ); + + void give( const TokenType& token ); + + /** + \brief give \p n token back + + Gives n tokens to BinT. Blocked process objects + could be activated by this call. + */ + void give( const TokenVec& tokens ); + + /// Number of tokens available + std::size_t getTokenNumber() const; + + /// Get a reference to the stored tokens + const StorageType& getTokenStore() const; + //@} + + /// get list of blocked process objects + const base::ProcessList& getWaitingProcesses() const; + +private: + /// token storage + StorageType tokenStorage_; + /// token count + std::size_t tokenCount_; + /// process management queue + Queue takeQueue_; + + /// Helper for quick access to the current simulation time + base::SimTime getCurrentTime() const; + /// Helper for quick access to the currently running object + base::Sched* getCurrentSched(); + /// Helper for quick access to the current process + base::Process* getCurrentProcess(); +}; + +/** \interface BinTObserver + + \author Ralf Gerstenberger + + \brief Observer for BinT specific events + + \sa BinT + + \since 2.1 +*/ +template < typename TokenT > +class BinTObserver { +public: + + typedef BinT< TokenT > BinType; + + virtual ~BinTObserver() {} + + /// Creation + virtual void onCreate( BinType* sender ) {} + + /// Failed attempt to take n token + virtual void onTakeFail( BinType* sender, std::size_t n ) {} + /// Successfull attempt to take n token + virtual void onTakeSucceed( BinType* sender, std::size_t n ) {} + /// Return of n token + virtual void onGive( BinType* sender, std::size_t n ) {} + + /// Change of token number + virtual void onChangeTokenNumber( BinType* sender, std::size_t oldTokenCount, + std::size_t newTokenCount ) {} +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_BINT_IMPL_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/port/PortData.h b/odemx-lite/include/odemx/synchronization/port/PortData.h new file mode 100644 index 0000000000000000000000000000000000000000..054c458dff3aceeda917e2332caa1b6b80150b67 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/port/PortData.h @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file PortData.h + + \author Ronald Kluth + + \date created at 2007/04/04 + + \brief Declaration of odemx::synchronization::PortData + + \sa PortT.h, PortT.cpp, PortHeadT.cpp, PortTailT.cpp + + \since 2.0 +*/ + +#ifndef ODEMX_PORTDATA_INCLUDED +#define ODEMX_PORTDATA_INCLUDED + +namespace odemx { +namespace synchronization { + +/** \class PortData + + \ingroup synch + + \author Ronald Kluth + + \brief %PortData is the default base class for port elements. + + \sa PortHeadT, PortTailT, PortT + + %PortData can be used as common base class for all objects that + are handled by ports. With default ports, all class types that + define elements such as messages to be passed through a port + must be derived from %PortData because default ports can only handle + pointers to subclasses of this type. + + \since 2.0 +*/ +class PortData +{ +protected: + /// Construction + PortData() {} + /// Copy Construction + PortData( const PortData& other ) {} + +public: + /// Destruction + virtual ~PortData() {} +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_PORTDATA_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/port/PortHeadImpl.h b/odemx-lite/include/odemx/synchronization/port/PortHeadImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..cd2410a7904f036974012e19e6b71b5f829de07c --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/port/PortHeadImpl.h @@ -0,0 +1,791 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//------------------------------------------------------------------------------ +/** + * @file PortHeadImpl.h + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Declaration and Implementation of odemx::synchronization::PortHeadT + * @see PortImpl.h, PortTailImpl.h + * @since 2.0 + */ + +#ifndef ODEMX_SYNC_PORTHEAD_IMPL_INCLUDED +#define ODEMX_SYNC_PORTHEAD_IMPL_INCLUDED + +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/DefaultSimulation.h> +#include <odemx/synchronization/Memory.h> +#include <odemx/synchronization/port/PortMode.h> +#include <odemx/synchronization/port/PortImpl.h> + +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + + +namespace odemx { +namespace synchronization { + +// forward declarations +template < typename > class PortTailT; +template < typename > class PortHeadTObserver; + +/** + * @ingroup synch + * @author Ronald Kluth + * @brief %PortHeadT provides read access to a port + * @see PortTailT, PortT + * + * This class manages read access to a limited internal buffer. + * It can be run in three different error modes according to + * PortMode. Calling @c get on an empty port head will either + * block the reader (and alert him upon availability), report + * an error, or return zero. + * + * @since 2.0 + */ +template < typename ElementT > +class PortHeadT +: public Memory // is a data::Producer +, public data::Observable< PortHeadTObserver< ElementT > > +, public std::enable_shared_from_this< PortHeadT< ElementT > > +{ +public: + /// Type of the elements the port can store + typedef ElementT ElementType; + /// Storage type of the internal buffer + typedef typename PortT< ElementType >::StorageType StorageType; + /// Size type of the internal buffer + typedef typename PortT< ElementType >::SizeType SizeType; + /// Pointer type to manage port head objects + typedef std::shared_ptr< PortHeadT< ElementType > > Ptr; + /// Pointer type to manage port tail objects + typedef std::shared_ptr< PortTailT< ElementType > > TailPtr; + /// Type of the compatible port head observer + typedef PortHeadTObserver< ElementType > ObserverType; + + /// Type of a selection function + typedef bool( base::Process::*ElementCondition ) ( ElementType ); + + /** + * @brief Creation for user-defined Simulation + * @param sim Reference to the simulation context + * @param label Label of the port, the head's label will be set to "label (head)" + * @param mode Port head's mode, default is WAITING_MODE + * @param limit Maximum number of elements, default is 10000 + * @param obs Initial observer + * @return Shared pointer to a newly constructed port head + */ + static Ptr create( base::Simulation& sim, const data::Label& label, + PortMode mode = WAITING_MODE, SizeType limit = 10000, ObserverType* obs = 0 ) + { + Ptr rv( new PortHeadT( sim, label, mode, limit, obs ) ); + rv->initPort(); +// rv->port_.reset( new PortType( sim, label, limit ) ); +// rv->port_->setHead( typename PortType::HeadPtr( rv ) ); + return rv; + } + + /// Destruction, managed by @c shared_ptr + virtual ~PortHeadT() + { + ODEMX_TRACE << log( "destroy" ).scope( typeid( PortHeadT< ElementType > ) ); + ODEMX_OBS_T( ObserverType, Destroy( this ) ); + } + + /** + \brief Port read access + \return Pointer holding the first port element, or an empty pointer + + This function is used to read information from a port. It also + responds according to the object's PortMode. In @c WAITING_MODE this + leads to the suspension of the calling Process. If the caller + is interrupted before receiving an element, it is reactivated + and the function returns an empty pointer. In @c ZERO_MODE a + miss only returns a null pointer, while in @c ERROR_MODE an error + will be sent additionally. + + \note The returned object is always dynamically allocated, which + is why an \c auto_ptr is used. This way, the caller never needs + to delete the return value. Checking for null pointer is done in + the following manner: + \code + std::unique_ptr< int > ptr = port.get(); + if( ptr.get() == 0 ) { + // handle null return value + } + else { + // use ptr like any other pointer + } + \endcode + */ + std::unique_ptr< ElementType > get() + { + ODEMX_TRACE << log( "get" ).detail( "partner", getPartner() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Get( this ) ); + + while( port_->isEmpty() ) + { + base::Sched* caller = getSimulation().getCurrentSched(); + + switch( mode_ ) + { + case WAITING_MODE: + if( caller == nullptr ) + { + error << log( "PortHeadT::get(): port in waiting mode called from environment" ) + .scope( typeid( PortHeadT< ElementType > ) ); + + return std::unique_ptr< ElementType >( nullptr ); + } + + if( caller->getSchedType() == base::Sched::PROCESS ) + { + + Memory::remember( caller ); + dynamic_cast< base::Process* >( caller )->sleep(); + + // PortHeadT::alert doesn't forget any remembered processes by itself. We have + // to delete them manually from the inner waiting list. + Memory::forget( caller ); + + // check for interruption of waiting period + if( dynamic_cast< base::Process* >( caller )->isInterrupted() ) + { + return std::unique_ptr< ElementType >( nullptr ); + } + } + else if( caller->getSchedType() == base::Sched::EVENT ) + { + // error: cannot send an event to sleep + error << log( "PortHeadT::get(): waiting mode not allowed for events" ) + .scope( typeid( PortHeadT< ElementType > ) ); + + return std::unique_ptr< ElementType >( nullptr ); + } + break; + + case ERROR_MODE: + error << log( "PortHeadT::get(): called on empty port" ) + .scope( typeid( PortHeadT< ElementType > ) ); + + return std::unique_ptr< ElementType >( nullptr ); + + case ZERO_MODE: + return std::unique_ptr< ElementType >( nullptr ); + } + } + + + // the Port was filled to the limit + bool wasFull = port_->isFull(); + + // remove first element from Port + std::unique_ptr< ElementType > first( port_->get() ); + + // alert waiting sender if the port was full and a tail is set + if( wasFull && port_->hasTail() ) + { + TailPtr tail = getTail(); + if( tail->waiting() ) + { + tail->alert(); + } + } + return first; + } + + /** + \brief Port read access based on criterion + \return Pointer holding the first port element conforming to the given criterion, or an empty pointer + + This function is used to read information from a port. It also + responds according to the object's PortMode. In @c WAITING_MODE this + leads to the suspension of the calling Process. If the caller + is interrupted before receiving an element, it is reactivated + and the function returns an empty pointer. In @c ZERO_MODE a + miss only returns a null pointer, while in @c ERROR_MODE an error + will be sent additionally. + + \note The returned object is always dynamically allocated, see PortHeadT< ElementType >::get() . + \since 3.0 + */ + std::unique_ptr< ElementType > get( ElementCondition sel ) + { + ODEMX_TRACE << log( "get" ).detail( "partner", getPartner() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Get( this ) ); + + bool foundSuitableElement = true; // if no sel function is given, every element in the port is fine + typename synchronization::PortHeadT< ElementType >::StorageType::iterator element; // remember the element we'll find + + // only Processes can check the elements in the port. + if ( sel && this->getSimulation() . getCurrentSched ()->getSchedType () == base::Sched::PROCESS ) { + foundSuitableElement = false; + + // check every element in the port if it confirms to the criterion sel + typename synchronization::PortHeadT< ElementType >::StorageType::iterator it; + + base::Process *current_process = static_cast<base::Process*> (this->getSimulation ().getCurrentSched ()); + + for (it = this->port_->begin (); ( it != this->port_->end () && !foundSuitableElement ); it++) + { + if ( ( foundSuitableElement = (current_process->*sel)(*it) ) ) + element = it; + } + } + + while( this->port_->isEmpty() || !foundSuitableElement ) + { + base::Sched* caller = this->getSimulation().getCurrentSched(); + + switch( this->mode_ ) + { + case WAITING_MODE: + if( caller == nullptr ) + { + error << log( "PortHeadT::get( ElementCondition ): port in waiting mode called from environment" ) + .scope( typeid( PortHeadT< ElementType > ) ); + + return std::unique_ptr< ElementType >( nullptr ); + } + + if( caller->getSchedType() == base::Sched::PROCESS ) + { + // unlike Memory::get(), Memory::get ( ElementCondition ) might try to add a + // Process more than once to the inner waiting list. We have to avoid that. + if (!Memory::processIsWaiting (*(static_cast< base::Process* >( caller )))) + Memory::remember( caller ); + + dynamic_cast< base::Process* >( caller )->sleep(); + + // check for interruption of waiting period + if( dynamic_cast< base::Process* >( caller )->isInterrupted() ) + { + Memory::forget( caller ); + return std::unique_ptr< ElementType >( nullptr ); + } + + // activation happend via Memory::alert () + + // if no selection function exists, then we handle this process as if it + // called get () + if (!sel) { + element = this->port_->inspectLastElement (); + foundSuitableElement = true; + } + else { + base::Process *current_process = static_cast<base::Process*> (this->getSimulation ().getCurrentSched ()); + + // Is the new element confirming to the criterion sel? If not, wake up other + // sleeping processes. + if (!(current_process->*sel)(*(this->port_->inspectLastElement ()))) { + const base::SchedList& waitingList = this->getWaiting (); + base::SchedList::const_iterator found = std::find( waitingList.begin(), waitingList.end(), current_process); + + if (found != waitingList.end ()) { + ++found; + if (found != waitingList.end ()) { + /* We found another waiting process */ + + // we know that this cast is ok, because only processes are allowed to wait + base::Process *next_process = static_cast<base::Process*>(*found); + next_process->alertProcess (this); + } + } else { + error << log ("PortHeadT: get ( ElementCondition ): Process wasn't in the waiting list") + .scope ( typeid ( PortHeadT< ElementType > ) ); + } + } else { + foundSuitableElement = true; + element = this->port_->inspectLastElement (); + Memory::forget( caller ); + } + } + } + else if( caller->getSchedType() == base::Sched::EVENT ) + { + // error: cannot send an event to sleep + error << log( "PortHeadT::get( ElementCondition ): waiting mode not allowed for events" ) + .scope( typeid( PortHeadT< ElementType > ) ); + + return std::unique_ptr< ElementType >( nullptr ); + } + break; + + case ERROR_MODE: + error << log( "PortHeadT::get( ElementCondition ): called on empty port" ) + .scope( typeid( PortHeadT< ElementType > ) ); + + return std::unique_ptr< ElementType >( nullptr ); + + case ZERO_MODE: + return std::unique_ptr< ElementType >( nullptr ); + } + } + + // the Port was filled to the limit + bool wasFull = this->port_->isFull(); + + // remove last element from Port + std::unique_ptr< ElementType > ret( this->port_->get (element) ); + + // alert waiting sender if the port was full and a tail is set + if( wasFull && this->port_->hasTail() ) + { + typename synchronization::PortHeadT< ElementType >::TailPtr tail = this->getTail(); + if( tail->waiting() ) + { + tail->alert(); + } + } + return ret; + } + + + /** + \brief Port access, put element back at front + \param element The element to put back into the buffer + \return @c true if the port element was successfully added at the front + + This function is used to put an element back at the front + of the internal port. + \note This function doesn't work as intended with PortHeadT< ElementType >::get ( ElementCondition ), + as we don't know where to put the given element in the queue. + */ + bool unGet( const ElementType& element ) + { + ODEMX_TRACE << log( "unGet" ).detail( "partner", getPartner() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, UnGet( this, element ) ); + + if( port_->isFull() ) + { + switch ( mode_ ) + { + case WAITING_MODE: + /* FALL TROUGH */ + case ERROR_MODE: + error << log( "PortHeadT::unGet(): called on full port" ) + .scope( typeid( PortHeadT< ElementType > ) ); + /* FALL TROUGH */ + case ZERO_MODE: + return false; + } + } + // insert PortData at the front of the Port queue + port_->unGet( element ); + return true; + } + + /** + \brief Get corresponding port tail + \return Pointer to the corresponding tail of this head + + This function provides access to the tail of a port head. + If it does not exist yet, it is created. + */ + TailPtr getTail() + { + TailPtr tail = port_->getTail(); + + // check if the tail pointer is empty + if( ! tail ) + { + // create new Tail + tail.reset( new PortTailT< ElementType >( getSimulation(), + port_->getLabel(), mode_, port_->getCapacity() ) ); + + // register new Tail with Head's Port + port_->setTail( typename PortType::TailPtr( tail ) ); + + // register Head's internal Port with the Tail + tail->port_ = this->port_; + } + return tail; + } + + /** + \brief Get maximum capacity of the internal port + \return Capacity of the buffer + + This function is used to determine the maximum number of + elements that can be buffered by the internal port. + + \sa setMaxCapacity() + */ + SizeType getMaxCapacity() + { + return port_->getCapacity(); + } + + /** + \brief Change maximum capacity of the port + \param limit The new maximum capacity of the internal port + + This function allows to change the maximum number of elements the + internal buffer can hold. + + \sa getMaxCapacity() + */ + void setMaxCapacity( SizeType limit ) + { + ODEMX_TRACE << log( "change max capacity" ) + .valueChange( port_->getCapacity(), limit ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_ATTR_T( ObserverType, MaxCapacity, port_->getCapacity(), limit ); + + port_->setCapacity( limit ); + } + + /// Determine the port head's mode + PortMode getMode() const + { + return mode_; + } + + /// Change the port head's mode + void setMode( PortMode newMode ) + { + ODEMX_TRACE << log( "change mode" ).valueChange( toString( mode_ ), toString( newMode ) ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_ATTR_T( ObserverType, Mode, mode_, newMode ); + + mode_ = newMode; + } + + /** + \brief Get current number of port elements + \return Current number of elements + + This method returns the current number of buffered elements. + */ + SizeType count() const + { + return port_->getElementCount(); + } + + /** + \brief Check for availability of an element + \return @c true if the port is not empty + + This function is used to determine whether an element is + available from the internal port. + */ + virtual bool isAvailable() + { + return ! port_->isEmpty(); + } + + /** + \brief Cut this port head from its tail + \return New port head of the old internal port + + This function will create a new internal port, which + is attached to this head. A new tail for that port must then be + requested via getTail(). Furthermore, a new port head will + be attached to the old internal port. That new head will be + returned. + + This provides the ability to insert a process into + the middle of a port connection, for example as a filter. + + \sa splice() + */ + Ptr cut() + { + // change + // old_Port_head -- old_Port -- old_Port_tail + // into + // old_Port_head -- new_Port (___get new tail___) + // new_Port_head -- old_Port -- old_Port_tail + // where + // old_Port_head == this + // return + // new_Port_head. + + ODEMX_TRACE << log( "cut" ).detail( "partner", getPartner() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Cut( this ) ); + + // remember old Port + PortPtr oldPort = port_; + + // create a new Head and thereby a new Port + Ptr newHead( new PortHeadT< ElementType >( + getSimulation(), + data::Label( "Cut " ) + oldPort->getLabel(), + mode_, oldPort->getCapacity() ) ); + + // get the new Port + PortPtr newPort = newHead->port_; + + // put the new head on the old Port + oldPort->setHead( typename PortType::HeadPtr( newHead ) ); + newHead->port_ = oldPort; + + // put the old head (== this) on the new Port + newPort->setHead( typename PortType::HeadPtr( this->shared_from_this() ) ); + port_ = newPort; + + return newHead; + } + + /** + \brief Splice two separate ports together + \param oldTail The tail of the port to which this head's buffer will be added + + This function is the reverse operation of cut(). It is used to join + two ports together. This head must be upstream of, i.e. before, + oldTail's port, which this buffer will be joined with. + The contents of this Port is added to oldTail's Port. If + the new head's buffer becomes non-empty, it is alerted. + + \warning Some objects become invalid with this operation! + This head, oldTail, and oldTail's Port should not be accessed anymore + after calling this method. + + \note This method does not check the maximum Port capacity before + splicing lists. + + \sa cut() + */ + void splice( TailPtr oldTail ) + { + // this PortHead is supposed to be upstream to the portTail oldTail: + // >> headsTail -- headsPort -- thisHead >> oldTail -- tailsPort -- tailsHead >> + // what remmains afterwards is this: + // >> headstail -- tailsPort -- tailsHead >> + // add the contents of headsPort to tailsPort + // destroy thisHead and oldTail + // alert the spliced PortHead if a significant state change happened + + ODEMX_TRACE << log( "splice" ).detail( "partner", getPartner() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Splice( this, oldTail ) ); + + // remember parts + Ptr tailsHead = oldTail->getHead(); // may be 0 + TailPtr headsTail = port_->getTail(); // may be 0 + PortPtr tailsPort = oldTail->port_; + PortPtr headsPort = port_; + + // and their element counts + int tailsCount = tailsPort->getElementCount(); + int headsCount = headsPort->getElementCount(); + + // append head's buffer to tail's buffer via std::list::splice() + if( headsCount > 0 ) + { + tailsPort->spliceBuffer( headsPort->getBuffer(), true ); + } + + // patch the head's tail onto tail's Port, which has it's own head, + // this PortHead becomes superfluous, requires pointers in both directions! + if( headsTail ) + { + tailsPort->setTail( headsTail ); + headsTail->port_ = tailsPort; + } + + // alert the new head if its Port becomes non-empty + if( (tailsCount == 0) && (headsCount > 0) && (tailsHead) ) + { + if( tailsHead->waiting() ) + { + tailsHead->alert(); + } + } + } + + /** + \brief Splice internal lists of two separate ports together + \param tail The tail of the port whose buffer will be added to this + \param append Determines whether to append or prepend tail's contents + + This function is used to join two ports' buffer contents together + in the same way as std::list::splice(). The contents of the \p + tail PortT will be moved to \p this port, where parameter \p append + can be used to specify whether the data will be appended or prepended + to this port. Default is append. + + \note This function does not check the maximum Port capacity before + splicing lists. + */ + void cppSplice( TailPtr tail, bool append = true ) + { + ODEMX_TRACE << log( "cpp splice" ).detail( "partner", getPartner() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, CppSplice( this, tail, append ) ); + + if( append ) + { + port_->spliceBuffer( tail->port_->getBuffer(), true ); + } + else + { + port_->spliceBuffer( tail->port_->getBuffer(), false ); + } + } + + /// Get the storage buffer, allows write access for splicing + const StorageType& getBuffer() const + { + return const_cast< const StorageType& >( port_->getBuffer() ); + } +private: + + friend class PortTailT< ElementType >; + + /** + \brief Alert the first stored process + + This function is designed to wake up suspended processes, + i.e. reschedule them at simulation time \c now when they + are waiting for an empty port to receive an element. Only + the first remembered process is alerted by the %PortHead. + */ + virtual void alert() + { + // simpler implementation than in Memory because get() does + // some checking already and only the first waiting Process is alerted + + if( ! Memory::waiting() ) + { + // warning: no object to wake + if ( mode_ != ZERO_MODE ) + { + warning << log( "PortHeadT::alert(): no process saved" ) + .scope( typeid( PortHeadT< ElementType > ) ); + } + return; + } + + // get() allows WAITING_MODE only for Processes, so cast is okay here + base::Process* rememberedObject = + static_cast< base::Process* >( Memory::getWaiting().front() ); + + ODEMX_TRACE << log( "alert" ).detail( "partner", rememberedObject->getLabel() ) + .scope( typeid( PortHeadT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Alert( this, rememberedObject ) ); + + // wake up the process + rememberedObject->alertProcess( this ); + } + + /// Get the label of the currently active Sched object, or the simulation + const data::Label& getPartner() + { + // return the current process or event, if one is active + if( getSimulation().getCurrentSched() != nullptr ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + else + { + return getSimulation().getLabel(); + } + } + +private: + /// Type of the internal port object + typedef PortT< ElementType > PortType; + /// Pointer type to manage the internal PortT object + typedef std::shared_ptr< PortType > PortPtr; + + PortPtr port_; ///< Pointer to the internal port object + PortMode mode_; ///< Mode for read requests + +protected: + /// Construction private, use @c create instead + PortHeadT( base::Simulation& sim, const data::Label& label, + PortMode mode = WAITING_MODE, SizeType limit = 10000, + ObserverType* obs = 0 ) + : Memory( sim, label + " (head)", IMemory::PORTHEAD ) + , data::Observable< ObserverType >( obs ) + , mode_( mode ) + { + ODEMX_TRACE << log( "create" ).scope( typeid( PortHeadT< ElementType > ) ); + ODEMX_OBS_T( ObserverType, Create( this ) ); + + this->port_.reset( new PortType( getSimulation(), label, limit ) ); + } + /// Connect the port head to the internal buffer, needed after construction + void initPort() + { + this->port_->setHead( this->shared_from_this() ); + } +private: + /// No copying + PortHeadT( const PortHeadT& ); + /// No assignment + PortHeadT& operator=( const PortHeadT& ); +}; + +/** + * @interface PortHeadTObserver + * @ingroup synch + * @author Ronald Kluth + * @brief Observer for PortHeadT-specific calls. + * @see PortHeadT + * @since 2.0 + */ +template < typename ElementT > +class PortHeadTObserver: public MemoryObserver { +public: + typedef ElementT ElementType; + typedef typename PortT< ElementType >::SizeType SizeType; + + virtual ~PortHeadTObserver() {} + + virtual void onDestroy( PortHeadT< ElementType >* sender ) {} ///< Destruction + + virtual void onGet( PortHeadT< ElementType >* sender ) {} + virtual void onUnGet( PortHeadT< ElementType >* sender, const ElementType& newElement ) {} + virtual void onCut( PortHeadT< ElementType >* sender ) {} + virtual void onSplice( PortHeadT< ElementType >* sender, + typename PortHeadT< ElementType >::TailPtr oldTail ) {} + virtual void onCppSplice( PortHeadT< ElementType >* sender, + typename PortHeadT< ElementType >::TailPtr oldTail, bool append ) {} + virtual void onAlert( PortHeadT< ElementType >* sender, base::Sched* alerted ) {} + + /// PortHead mode change + virtual void onChangeMode( PortHeadT< ElementType >* sender, + PortMode oldMode, PortMode newMode ) {} + /// PortHead capacity change + virtual void onChangeMaxCapacity( PortHeadT< ElementType >* sender, + SizeType oldLimit, SizeType newLimit ) {} +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_PORTHEAD_IMPL_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/port/PortImpl.h b/odemx-lite/include/odemx/synchronization/port/PortImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..e9d4c9739ab3c5025e4e21593f65b2a31fc05979 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/port/PortImpl.h @@ -0,0 +1,291 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//------------------------------------------------------------------------------ +/** + * @file PortImpl.h + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Declaration and Implementation of odemx::synchronization::PortT + * @see PortHeadImpl.h, PortTailImpl.h + * @since 2.0 + */ + +#ifndef ODEMX_SYNC_PORT_IMPL_INCLUDED +#define ODEMX_SYNC_PORT_IMPL_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/util/TypeToString.h> + +#include <list> + +#ifdef _MSC_VER +#include <memory> +#else +#include <memory> +#endif + + +namespace odemx { + +//----------------------------------------------------------forward declarations + +namespace base { class Simulation; } + +namespace synchronization { + +template < typename > class PortHeadT; +template < typename > class PortTailT; + +//-----------------------------------------------------------header declarations + +/** + * @ingroup synch + * @author Ronald Kluth + * @brief %PortT is implements the internal buffer for PortHeadT and PortTailT + * @see PortHeadT, PortTailT + * + * This internal class manages the limited buffer that is the base + * for a communications port. It maintains references to its port tail, + * which describes the input interface, and its port head, which is the + * output interface of a port. + * + * @note In order to use and access ports, you need to create either a + * PortHeadT or PortTailT object, which, respectively, provide the read + * and write interface to the buffer. + * + * @since 2.0 + */ +template < typename ElementT > +class PortT +: public data::Producer +{ +public: + /// Destruction + virtual ~PortT() + { + if( ! buffer_.empty() ) + { + warning << log( "PortT::~PortT(): port not empty" ) + .scope( typeid( PortT< ElementType > ) ); + } + } + + /// Type of the buffer elements + typedef ElementT ElementType; + /// Storage type for the buffer + typedef std::list< ElementType > StorageType; + /// Storage type for the buffer + typedef typename StorageType::size_type SizeType; + /// Head pointer type + typedef std::weak_ptr< PortHeadT< ElementType > > HeadPtr; + /// Tail pointer type + typedef std::weak_ptr< PortTailT< ElementType > > TailPtr; + +private: + friend class PortHeadT< ElementType >; + friend class PortTailT< ElementType >; + + /// Construction, used only by head / tail + PortT( base::Simulation& sim, const data::Label& label, SizeType limit ) + : data::Producer( sim, label ) + , maxCapacity_( limit ) + , elementCount_( 0 ) + { + // check for invalid port capacity + if( limit == 0 ) + { + error << log( "PortT(): attempt to create Port with invalid capacity, using default" ) + .scope( typeid( PortT< ElementType > ) ); + + maxCapacity_ = defaultLimit; + } + + statistics << param( "element type", odemx::typeToString( typeid( ElementType ) ) ) + .scope( typeid( PortT< ElementType > ) ); + statistics << param( "maximum capacity", maxCapacity_ ) + .scope( typeid( PortT< ElementType > ) ); + } + + /// Append an element to the buffer + void put( const ElementType& element ) + { + buffer_.push_back( element ); + ++elementCount_; + + statistics << count( "put calls" ).scope( typeid( PortT< ElementType > ) ); + statistics << update( "buffer size", elementCount_ ) + .scope( typeid( PortT< ElementType > ) ); + } + + /// Get the first element from the buffer (and remove it) + std::unique_ptr< ElementType > get() + { + std::unique_ptr< ElementType > rv( new ElementType( buffer_.front() ) ); + buffer_.pop_front(); + --elementCount_; + + statistics << count( "get calls" ).scope( typeid( PortT< ElementType > ) ); + statistics << update( "buffer size", elementCount_ ) + .scope( typeid( PortT< ElementType > ) ); + return rv; + } + + /// Get a specific element from the buffer (and remove it) + std::unique_ptr< ElementType > get(typename StorageType::iterator it) + { + std::unique_ptr< ElementType > rv( new ElementType( *it ) ); + buffer_.erase (it); + --elementCount_; + + statistics << count( "get calls" ).scope( typeid( PortT< ElementType > ) ); + statistics << update( "buffer size", elementCount_ ) + .scope( typeid( PortT< ElementType > ) ); + return rv; + } + + /// Put an element back at the front of the buffer + /// TODO doesn't work, if we can take an arbitrary element + /// XXX nochmal darüber nachdenken (generell) + void unGet( const ElementType& element ) + { + buffer_.push_front( element ); + ++elementCount_; + + statistics << count( "unGet calls" ).scope( typeid( PortT< ElementType > ) ); + statistics << update( "buffer size", elementCount_ ) + .scope( typeid( PortT< ElementType > ) ); + } + + /// XXX get an iterator to the contained buffer + typename StorageType::iterator begin () { + return buffer_.begin (); + } + + /// XXX + typename StorageType::iterator end () { + return buffer_.end (); + } + + /// TODO const? Reference? + /// TODO note: no error checks! we assume the user isn't dumb + typename StorageType::iterator inspectLastElement () { + return --(buffer_.end ()); + } + + + /// Check whether the buffer contains elements + bool isEmpty() const + { + return buffer_.empty(); + } + + /// Check whether the internal buffer is already full + bool isFull() const + { + return elementCount_ >= maxCapacity_; + } + + /// Check if a head exists + bool hasHead() const + { + return ! head_.expired(); + } + + /// Set a new head for this port + void setHead( HeadPtr head ) + { + head_ = head; + } + + /// Get a pointer to the port's head, may be empty + std::shared_ptr< PortHeadT< ElementType > > getHead() const + { + return head_.lock(); + } + + /// Check if a tail exists + bool hasTail() const + { + return ! tail_.expired(); + } + + /// Set a new tail for the port + void setTail( TailPtr tail ) + { + tail_ = tail; + } + + /// Get a pointer to the port's tail, may be empty + std::shared_ptr< PortTailT< ElementType > > getTail() const + { + return tail_.lock(); + } + + /// Change the maximum capacity of the internal buffer + void setCapacity( SizeType limit ) + { + maxCapacity_ = limit; + } + + /// Get the maximum allowed capacity of the internal buffer + SizeType getCapacity() const + { + return maxCapacity_; + } + + /// Check the number of elements currently stored in the buffer + SizeType getElementCount() const + { + return elementCount_; + } + + /// Move items from @c buffer to this port's storage buffer + void spliceBuffer( StorageType& buffer, bool append ) + { + elementCount_ += buffer.size(); + if( append ) + { + buffer_.splice( buffer_.end(), buffer ); + } + else + { + buffer_.splice( buffer_.begin(), buffer ); + } + statistics << update( "buffer size", elementCount_ ) + .scope( typeid( PortT< ElementType > ) ); + } + + /// Get the storage buffer, allows write access for splicing + StorageType& getBuffer() + { + return buffer_; + } + +private: + SizeType maxCapacity_; ///< maximum buffer capacity + SizeType elementCount_; ///< current number of elements in the buffer + StorageType buffer_; ///< internal buffer for elements of type ElementType + HeadPtr head_; ///< corresponding Head interface + TailPtr tail_; ///< corresponding Tail interface + /// Default value for maximum port capacity + static const SizeType defaultLimit = 10000; +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_PORT_IMPL_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/port/PortMode.h b/odemx-lite/include/odemx/synchronization/port/PortMode.h new file mode 100644 index 0000000000000000000000000000000000000000..6120eae25166758eeb740d1d0f86a2956c13ec9d --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/port/PortMode.h @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//------------------------------------------------------------------------------ +/** + * @file PortMode.h + * @author Ronald Kluth + * @date created at 2009/09/21 + * @brief Declaration of enum odemx::synchronization::PortMode + * @see PortHeadImpl.h, PortTailImpl.h + * @since 3.0 + */ + +#ifndef ODEMX_SYNC_PORTMODE_INCLUDED +#define ODEMX_SYNC_PORTMODE_INCLUDED + +namespace odemx { +namespace synchronization { + +/** + * @ingroup synch + * @author Ronald Kluth + * @brief Port modes + * @see PortHeadT PortTailT + * + * Since ports implement a limited buffer, a behavior needs to be + * defined for when a port is full, but an element is to be inserted, + * or when a port is empty and some process is trying to read from it. + * Modes for port head and corresponding port tail can differ. + */ +enum PortMode +{ + ERROR_MODE, ///< error when full/empty + WAITING_MODE, ///< context switch when full/empty + ZERO_MODE ///< ignore caller when full/empty, return 0 +}; + +inline std::string toString( const PortMode mode ) +{ + switch( mode ) + { + case ERROR_MODE: return "ERROR_MODE"; + case WAITING_MODE: return "WAITING_MODE"; + case ZERO_MODE: return "ZERO_MODE"; + } + return "ERROR"; +} + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_PORTMODE_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/port/PortTailImpl.h b/odemx-lite/include/odemx/synchronization/port/PortTailImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..4d25c81e881a87413374c720ee16586c5176b052 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/port/PortTailImpl.h @@ -0,0 +1,546 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//------------------------------------------------------------------------------ +/** + * @file PortTailImpl.h + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Declaration and Implementation of odemx::synchronization::PortTailT + * @see PortHeadImpl.h, PortImpl.h + * @since 2.0 + */ + +#ifndef ODEMX_SYNC_PORTTAIL_INCLUDED +#define ODEMX_SYNC_PORTTAIL_INCLUDED + +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/DefaultSimulation.h> +#include <odemx/synchronization/Memory.h> +#include <odemx/synchronization/port/PortMode.h> +#include <odemx/synchronization/port/PortImpl.h> +#include <odemx/data/Observable.h> + +namespace odemx { +namespace synchronization { + +// forward declarations +template < typename > class PortHeadT; +template < typename > class PortTailTObserver; + +/** + * @ingroup synch + * @author Ronald Kluth + * @brief %PortTailT provides write access to a port + * @see PortHeadT, PortT + * + * This class manages write access to a limited internal buffer. + * It can be run in three different error modes according to + * PortMode. Calling @c put on a full port will either block + * the sender (and alert him upon availability), report an error, + * or return zero. + * + * @since 2.0 + */ +template < typename ElementT > +class PortTailT +: public Memory // is a data::Producer +, public data::Observable< PortTailTObserver< ElementT > > +, public std::enable_shared_from_this< PortTailT< ElementT > > +{ +public: + /// Type of the elements the port can store + typedef ElementT ElementType; + /// Storage type of the internal buffer + typedef typename PortT< ElementType >::StorageType StorageType; + /// Size type of the internal buffer + typedef typename PortT< ElementType >::SizeType SizeType; + /// Pointer type to manage port tail objects + typedef std::shared_ptr< PortTailT< ElementType > > Ptr; + /// Pointer type to manage port head objects + typedef std::shared_ptr< PortHeadT< ElementType > > HeadPtr; + /// Type of the compatible port head observer + typedef PortTailTObserver< ElementType > ObserverType; + + /** + * @brief Creation for user-defined Simulation + * @param sim Reference to the simulation context + * @param label Label of the port, the tail's label will be set to "label (tail)" + * @param mode Port tail's mode, default is WAITING_MODE + * @param limit Maximum number of elements, default is 10000 + * @param obs Initial observer + * @return Shared pointer to a newly constructed port tail + */ + static Ptr create( base::Simulation& sim, const data::Label& label, + PortMode mode = WAITING_MODE, SizeType limit = 10000, ObserverType* obs = 0 ) + { + Ptr rv( new PortTailT( sim, label, mode, limit, obs ) ); + rv->initPort(); +// rv->port_.reset( new PortType( sim, label, limit ) ); +// rv->port_->setTail( typename PortType::TailPtr( rv ) ); + return rv; + } + + /// Destruction, managed by @c shared_ptr + virtual ~PortTailT() + { + ODEMX_TRACE << log( "destroy" ).scope( typeid( PortTailT< ElementType > ) ); + ODEMX_OBS_T( ObserverType, Destroy( this ) ); + } + + /** + \brief Port write access + \param newElement The element to be inserted into the port + \return @c 1 upon success, @c 0 in @c ZERO_MODE or interrupt(), else @c -1 + + This function is used to insert an element into a port. It also + responds according to the tail's PortMode. In @c WAITING_MODE, the + calling Process will be suspended if the Port is already full. When + space becomes available, waiting callers will be alerted in a + FIFO-manner. If a blocked caller is interrupted, the Process will be + activated immediately and put() returns 0. + */ + int put( const ElementType& newElement ) + { + ODEMX_TRACE << log( "put" ).detail( "partner", getPartner() ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Put( this, newElement ) ); + + while( port_->isFull() ) + { + base::Sched* caller = getSimulation().getCurrentSched(); + + switch ( mode_ ) + { + case WAITING_MODE: + if ( caller == 0 ) + { + error << log( "PortTailT::put(): port in waiting mode called from environment" ) + .scope( typeid( PortTailT< ElementType > ) ); + return -1; + } + + if ( caller->getSchedType() == base::Sched::PROCESS ) + { + Memory::remember( caller ); + dynamic_cast< base::Process* >( caller )->sleep(); + + // check for interruption of waiting period + if( dynamic_cast< base::Process* >( caller )->isInterrupted() ) + { + Memory::forget( caller ); + return 0; + } + } + else if ( caller->getSchedType() == base::Sched::EVENT ) + { + // error: cannot send an event to sleep + error << log( "PortTailT::put(): waiting mode not allowed for events" ) + .scope( typeid( PortTailT< ElementType > ) ); + return -1; + } + break; + + case ERROR_MODE: + error << log( "PortTailT::put(): cannot add element to full port" ) + .scope( typeid( PortTailT< ElementType > ) ); + return -1; + + case ZERO_MODE: + return 0; + } + } + + // insert new element + port_->put( newElement ); + + // notify waiting Processes of newly inserted element + if( port_->hasHead() ) + { + HeadPtr head = getHead(); + if( head->waiting() ) + { + head->alert(); + } + } + return 1; // success + } + + /** + \brief Get corresponding port head + \return Pointer to the corresponding head to this tail + + This function provides access to the head of a port tail. + If it does not exist yet, it is created. + */ + HeadPtr getHead() + { + HeadPtr head = port_->getHead(); + + // check if the pointer is empty + if( ! head ) + { + // create new Head + head.reset( new PortHeadT< ElementType >( getSimulation(), + port_->getLabel(), mode_, port_->getCapacity() ) ); + + // register new Head with Tail's Port + port_->setHead( typename PortType::HeadPtr( head ) ); + + // register Tail's internal Port with the Head + head->port_ = this->port_; + } + return head; + } + + /** + \brief Get maximum capacity of the internal port + \return Capacity of the buffer + + This function is used to determine the maximum number of + elements that can be buffered by the internal port. + + \sa setMaxCapacity() + */ + SizeType getMaxCapacity() + { + return port_->getCapacity(); + } + + /** + \brief Change maximum capacity of the port + \param limit The new maximum capacity of the internal port + + This function allows to change the maximum number of elements the + internal buffer can hold. + + \sa getMaxCapacity() + */ + void setMaxCapacity( SizeType limit ) + { + ODEMX_TRACE << log( "change max capacity" ) + .valueChange( port_->getCapacity(), limit ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_ATTR_T( ObserverType, MaxCapacity, port_->getCapacity(), limit ); + + port_->setCapacity( limit ); + } + + /// Determine the port tail's mode + PortMode getMode() const + { + return mode_; + } + + /// Change the port tail's mode + void setMode( PortMode newMode ) + { + ODEMX_TRACE << log( "change mode" ).valueChange( toString( mode_ ), toString( newMode ) ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_ATTR_T( ObserverType, Mode, mode_, newMode ); + + mode_ = newMode; + } + + /** + \brief Get current number of port elements + \return Current number of elements + + This method returns the current number of buffered elements. + */ + SizeType count() const + { + return port_->getElementCount(); + } + + /** + \brief Check for availability of buffer space + \return @c true if the port is not full + + This function is used to determine whether there is space + available in the internal port. + */ + virtual bool isAvailable() + { + return ! port_->isFull(); + } + + /** + \brief Cut this port tail from its head + \return New port tail + + This function will create a new internal port, which + is attached to this tail. A new head for that port must then be + requested via getHead(). Furthermore, a new port tail will + be attached to the old internal port. That new tail will be + returned. + + This provides the ability to insert a process into + the middle of a port connection, for example as a filter. + + \sa splice() + */ + Ptr cut() + { + // change + // old_Port_head -- old_Port -- old_Port_tail + // into + // old_Port_head -- old_Port -- new_Port_tail + // (__get new head___) new_Port -- old_Port_tail + // where + // old_Port_tail == this + // return + // new_Port_tail. + + ODEMX_TRACE << log( "cut" ).detail( "partner", getPartner() ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Cut( this ) ); + + // remember old Port + PortPtr oldPort = port_; + + // create a new Tail and thereby a new Port + Ptr newTail( new PortTailT< ElementType >( + getSimulation(), + data::Label( "Cut " ) + oldPort->getLabel(), + mode_, oldPort->getCapacity() ) ); + + // get the new Port + PortPtr newPort = newTail->port_; + + // put the new tail on the old Port + oldPort->setTail( typename PortType::TailPtr( newTail ) ); + newTail->port_ = oldPort; + + // put the old tail (==this) on the new Port + newPort->setTail( typename PortType::TailPtr( this->shared_from_this() ) ); + port_ = newPort; + + return newTail; + } + + /** + \brief Splice two separate ports together + \param oldHead + the tail of the port to which this head's buffer will be attached + + This function is used to join two ports together. This tail must + be downstream of, i.e. positioned after, oldHead's port, which + this buffer will be joined with. The contents of this Port + is added to oldHead's Port. + + \warning Some objects become invalid with this operation! + This tail, oldHead, and this Port should not be accessed anymore after + calling this method. + + \note This method does not check the maximum Port capacity before + splicing lists. + + \sa cut() + */ + void splice( HeadPtr oldHead ) + { + // this PortTail is supposed to be downstream to the PortHead oldHead: + // >> headsTail -- headsPort -- oldHead >> thisTail -- tailsPort -- tailsHead >> + + ODEMX_TRACE << log( "splice" ).detail( "partner", getPartner() ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Splice( this, oldHead ) ); + + oldHead->splice( this->shared_from_this() ); + } + + /** + \brief Splice internal lists of two separate ports together + \param head The head of the port whose buffer will be added to this + \param append Determines whether to append or prepend head's contents + + This function is used to join two ports' buffer contents together + in the same way as std::list::splice(). The contents of the \p + tail PortT will be moved to \p this port, where parameter \p append + can be used to specify whether the data will appended or prepended + to this port. Default is append. + + \note This function does not check the maximum Port capacity before + splicing lists. + */ + void cppSplice( HeadPtr head, bool append = true ) + { + ODEMX_TRACE << log( "cpp splice" ).detail( "partner", getPartner() ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, CppSplice( this, head, append ) ); + + if( append ) + { + port_->spliceBuffer( head->port_->getBuffer(), true ); + } + else + { + port_->spliceBuffer( head->port_->getBuffer(), false ); + } + } + + /** + \brief Determine free space of the port + \return Number of elements that the port can still take in + + This function returns the remaining available space + of the internal buffer. + */ + SizeType getAvailableSpace() + { + return port_->getCapacity() - port_->getElementCount(); + } + + /// Get the storage buffer, allows write access for splicing + const StorageType& getBuffer() const + { + return const_cast< const StorageType& >( port_->getBuffer() ); + } + +private: + + friend class PortHeadT< ElementType >; + + /** + \brief Alert the first stored process + + This function is designed to wake up suspended processes, + i.e. reschedule them at simulation time \c now when they + are waiting for a full port to become available again. Only + the first remembered process is alerted by the port tail. + */ + virtual void alert() + { + // simpler implementation than in Memory because put() does + // some checking already and only the first waiting Process is alerted + + if( ! Memory::waiting() ) + { + // warning: no object to wake + if ( mode_ != ZERO_MODE ) + { + warning << log( "PortTailT::alert(): no process saved" ) + .scope( typeid( PortTailT< ElementType > ) ); + } + return; + } + + // put() allows WAITING_MODE only for Processes, so cast is okay here + base::Process* rememberedObject = + static_cast< base::Process* >( Memory::getWaiting().front() ); + + ODEMX_TRACE << log( "alert" ).detail( "partner", rememberedObject->getLabel() ) + .scope( typeid( PortTailT< ElementType > ) ); + + ODEMX_OBS_T( ObserverType, Alert( this, rememberedObject ) ); + + // wake up the process + rememberedObject->alertProcess( this ); + Memory::forget( rememberedObject ); + } + + /// Get the label of the currently active Sched object, or the simulation + const data::Label& getPartner() + { + // return the current process or event, if one is active + if( getSimulation().getCurrentSched() != 0 ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + else + { + return getSimulation().getLabel(); + } + } + +private: + + /// Type of the internal port object + typedef PortT< ElementType > PortType; + /// Pointer type to manage the internal PortT object + typedef std::shared_ptr< PortType > PortPtr; + + PortPtr port_; ///< Pointer to the internal port object + PortMode mode_; ///< Mode for read requests + +protected: + /// Construction private, use @c create instead + PortTailT( base::Simulation& sim, const data::Label& label, + PortMode mode = WAITING_MODE, SizeType limit = 10000, + ObserverType* obs = 0 ) + : Memory( sim, label + " (tail)", IMemory::PORTTAIL ) + , data::Observable< ObserverType >( obs ) + , mode_( mode ) + { + ODEMX_TRACE << log( "create" ).scope( typeid( PortTailT< ElementType > ) ); + ODEMX_OBS_T( ObserverType, Create( this ) ); + + this->port_.reset( new PortType( getSimulation(), label, limit ) ); + } + /// Connect the port tail to the internal buffer, needed after construction + void initPort() + { + this->port_->setTail( this->shared_from_this() ); + } +private: + /// No copying + PortTailT( const PortTailT& ); + /// No assignment + PortTailT& operator=( const PortTailT& ); +}; + + +/** + * @interface PortTailTObserver + * @author Ronald Kluth + * @brief Observer for PortTailT-specific calls. + * @see PortTailT + * @since 2.0 + */ +template < typename ElementT > +class PortTailTObserver: public MemoryObserver { +public: + typedef ElementT ElementType; + typedef typename PortT< ElementType >::SizeType SizeType; + + virtual ~PortTailTObserver() {} + + virtual void onDestroy( PortTailT< ElementType >* sender ) {} ///< Destruction + + virtual void onPut( PortTailT< ElementType >* sender, const ElementType& newElement ) {} + virtual void onCut( PortTailT< ElementType >* sender ) {} + virtual void onSplice( PortTailT< ElementType >* sender, typename PortTailT< ElementType >::HeadPtr oldHead ) {} + virtual void onCppSplice( PortTailT< ElementType >* sender, typename PortTailT< ElementType >::HeadPtr oldHead, bool append ) {} + virtual void onAlert( PortTailT< ElementType >* sender, base::Sched* alerted ) {} + + /// PortTail mode change + virtual void onChangeMode( PortTailT< ElementType >* sender, PortMode oldMode, PortMode newMode ) {} + /// PortTail capacity change + virtual void onChangeMaxCapacity( PortTailT< ElementType >* sender, SizeType oldMax, SizeType newMax ) {} +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_SYNC_PORTTAIL_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/res/ResT.cpp b/odemx-lite/include/odemx/synchronization/res/ResT.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6f46045ec11f5e1b98f6b5d53bca663473c85a0 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/res/ResT.cpp @@ -0,0 +1,203 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ResT.cpp + + \author Ronald Kluth + + \date created at 2008/02/18 + + \brief Definition of odemx::ResT + + \sa ResT.h + + \since 2.1 +*/ + +#include <odemx/base/Process.h> +#include <odemx/synchronization/res/ResT.h> + +#include <vector> + +namespace odemx { +namespace synchronization { + +template < typename Token > +ResT< Token >::ResT( base::Simulation& sim, + const data::Label& label, + std::vector< Token >& initialResources, + ResTObserver< Token >* o /* = 0*/ ) +: ResTBase< Token >( sim, label, initialResources, o ), + data::Observable< ResTObserver< Token > >( o ) +{ + // trace and stats in base class + + // observer + ODEMX_OBS_T(ResTObserver<Token>, Create(this)); +} + +template < typename Token > +ResT<Token>::~ResT() +{ + // observer + ODEMX_OBS_T(ResTObserver<Token>, Destroy(this)); +} + +template < typename Token > +Token* ResT< Token >::acquire() +{ + // get a return vector using acquire( n ) below + std::vector< Token* > v = acquire( 1 ); + + // return the first element of the vector + if( ! v.empty() ) + return v.front(); + + // or 0, if nothing was returned (i.e. error or interrupt) + return 0; +} + +template < typename Token > +const std::vector< Token* > ResT< Token >::acquire( std::size_t n ) +{ + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + // error: resource handling only implemented for processes + error << this->log( "ResT::acquire(): called by non-Process object" ).scope( typeid(ResT<Token>) ); + return std::vector< Token* >(); + } + + if( n > ResTBase< Token >::tokenLimit ) + { + warning << this->log( "ResT::acquire(): requesting more than max resources will always block" ) + .scope( typeid(ResT<Token>) ); + } + + base::Process* currentProcess = getCurrentProcess(); + base::SimTime waitTime = 0; + + // compute order of service + ResTBase< Token >::acquireWait.inSort( currentProcess ); + + if( n > ResTBase< Token >::tokenNumber || + ResTBase< Token >::acquireWait.getTop() != currentProcess ) + { + // not enough tokens or not the first process in queue + + ODEMX_TRACE << this->log( "acquire failed" ) + .detail( "partner", currentProcess->getLabel() ) + .detail( "requested tokens", n ) + .scope( typeid(ResT<Token>) ); + + // observer + ODEMX_OBS_T(ResTObserver<Token>, AcquireFail(this, n)); + + // statistics + base::SimTime waitStart = getCurrentTime(); + + // block execution + while( n > ResTBase< Token >::tokenNumber || + ResTBase< Token >::acquireWait.getTop() != currentProcess ) + { + currentProcess->sleep(); + + // handle interrupt + if( currentProcess->isInterrupted() ) + { + ResTBase< Token >::acquireWait.remove( currentProcess ); + return std::vector< Token* >(); + } + } + + // block released + // statistics + waitTime = getCurrentTime() - waitStart; + } + + ODEMX_TRACE << this->log( "change token number" ).valueChange( ResTBase<Token>::tokenNumber, ResTBase<Token>::tokenNumber - n ) + .scope( typeid(ResT<Token>) ); + + // observer + ODEMX_OBS_ATTR_T(ResTObserver<Token>, TokenNumber, ResTBase< Token >::tokenNumber, ResTBase< Token >::tokenNumber-n); + + // acquire token + ResTBase< Token >::tokenNumber -= n; + + // fill return vector with pointers to free resource objects + typename std::map< Token*, base::Process* >::iterator i; + std::vector< Token* > availableTokens; + + std::size_t acquired = 0; + for( i = ResTBase< Token >::tokenInfo.begin(); + i != ResTBase< Token >::tokenInfo.end() && acquired < n; + ++i ) + { + // if resource available, store the current user in tokenInfo + // and add the resource to the return vector + if( i->second == 0 ) + { + availableTokens.push_back( i->first ); + i->second = currentProcess; + ++acquired; + } + } + + ODEMX_TRACE << this->log( "acquire succeeded" ) + .detail( "partner", currentProcess->getLabel() ) + .detail( "requested tokens", n ) + .scope( typeid(ResT<Token>) ); + + // statistics + statistics << this->count( "users" ).scope( typeid(ResT<Token>) ); + statistics << this->update( "tokens", ResTBase< Token >::tokenNumber ).scope( typeid(ResT<Token>) ); + statistics << this->update( "wait time", waitTime ).scope( typeid(ResT<Token>) ); + + // observer + ODEMX_OBS_T(ResTObserver<Token>, AcquireSucceed(this, n)); + + // remove process from queue + ResTBase< Token >::acquireWait.remove( currentProcess ); + + // awake next waiting process + awakeFirst( ResTBase< Token >::getAcquireWait() ); + + // return tokens + return availableTokens; +} + +//-----------------------------------------------------------------------helpers + +//template < typename Token > +//base::SimTime ResT< Token >::getCurrentTime() +//{ +// return data::Producer::getSimulation().getTime(); +//} +// +//template < typename Token > +//odemx::base::Process* ResT< Token >::getCurrentProcess() +//{ +// return data::Producer::getSimulation().getCurrentProcess(); +//} +// +//template < typename Token > +//odemx::base::Sched* ResT< Token >::getCurrentSched() +//{ +// return data::Producer::getSimulation().getCurrentSched(); +//} + +} } // namespace odemx::sync diff --git a/odemx-lite/include/odemx/synchronization/res/ResT.h b/odemx-lite/include/odemx/synchronization/res/ResT.h new file mode 100644 index 0000000000000000000000000000000000000000..428008cc9c1f1b345e2fb0cf56bd4b4f60c56d91 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/res/ResT.h @@ -0,0 +1,148 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file res/ResT.h + + \author Ronald Kluth + + \date created at 2008/02/18 + + \brief Declaration of odemx::synchronization::ResT and observer + + \note This header file is not meant for inclusion, use + odemx/synchronization/ResTemplate.h instead. + + \sa ResT.cpp + + \since 2.1 +*/ + +#ifndef ODEMX_RES_T_INCLUDED +#define ODEMX_RES_T_INCLUDED + +#include <odemx/synchronization/res/ResTBase.h> + +namespace odemx { +namespace synchronization { + +// forward declaration +template < typename > class ResTObserver; + +/** \class ResT + + \author Ronald Kluth + + \brief ResT is a resource holding objects of type Token + + \note ResT supports Observation + \note ResT supports Trace + + ResT is a resource for synchronizing Process objects. A process is blocked + in acquire() if the requested number of tokens is greater than the available + number of tokens. It is reactivated when enough tokens are released to the resource. + If multiple process objects are waiting for reactivation, process-priority and + FIFO-strategy are used to choose the process. + + \since 2.1 +*/ +template < typename Token > +class ResT: + public ResTBase< Token >, // is a data producer + public data::Observable< ResTObserver< Token > > +{ +public: + + using data::Producer::trace; + using data::Producer::debug; + using data::Producer::info; + using data::Producer::warning; + using data::Producer::error; + using data::Producer::fatal; + using data::Producer::statistics; + using data::Producer::log; + using data::Producer::param; + using data::Producer::count; + using data::Producer::update; + using data::Producer::reset; + + using ResTBase<Token>::getCurrentTime; + using ResTBase<Token>::getCurrentSched; + using ResTBase<Token>::getCurrentProcess; + + /** + * \copydoc ResTBase(Simulation*,Label,std::vector<Token>&,ResTBaseObserver<Token>*) + */ + ResT( base::Simulation& sim, const data::Label& l, + std::vector< Token >& initialResources, + ResTObserver< Token >* o = 0 ); + + /// Destruction + virtual ~ResT(); + + /** + \name Token usage + + These functions provide access for resource usage by Processes. + Tokens can be requested and thus acquired when then are + available. When the tokens are not needed anymore, the owning + Process can release them. + + @{ + */ + /** + \brief acquire a token + + If there are no tokens in ResT the current process is blocked. + */ + virtual Token* acquire(); + + /** + \brief acquire \p n token + + If there are not enough tokens in ResT the current + process is blocked. + */ + const std::vector< Token* > acquire( std::size_t n ); +}; + +/** \interface ResTObserver + + \author Ronald Kluth + + \brief Observer for ResT specific events + + \sa ResT + + \since 2.1 +*/ +template < typename Token > +class ResTObserver: public ResTBaseObserver< Token > { +public: + typedef typename ResTBaseObserver< Token >::ResType ResType; + + virtual ~ResTObserver() {} + + /// Failed attempt to acquire n token + virtual void onAcquireFail(ResType* sender, std::size_t n) {} + /// Successful attempt to acquire n token + virtual void onAcquireSucceed(ResType* sender, std::size_t n) {} +}; + +} } // namespace odemx::synchronization + +#endif /* ODEMX_RES_T_INCLUDED */ diff --git a/odemx-lite/include/odemx/synchronization/res/ResTBase.cpp b/odemx-lite/include/odemx/synchronization/res/ResTBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f2ac3daca02afa08586f8952f6f893ec5920959 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/res/ResTBase.cpp @@ -0,0 +1,446 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ResTBase.cpp + + \author Ronald Kluth + + \date created at 2008/02/18 + + \brief Implementation of odemx::sync::ResTBase + + \sa ResTBase.h + + \since 2.1 +*/ + +#include <odemx/base/DefaultSimulation.h> +#include <odemx/synchronization/res/ResTBase.h> + +#include <odemx/base/Process.h> + +namespace odemx { +namespace synchronization { + +template < typename Token > +ResTBase< Token >::ResTBase( base::Simulation& sim, + const data::Label& label, + typename ResTBase< Token >::TokenVec& initialResources, + typename ResTBase< Token >::ObserverType* o /* = 0*/ ) +: data::Producer( sim, label ) +, data::Observable< ResTBaseObserver< Token > >( o ) +, tokenLimit( initialResources.size() ) +, tokenStore( initialResources.begin(), initialResources.end() ) +, acquireWait( sim, label + " acquire queue" ) +{ + // tokenStore already filled in initializer list + + // set initial tokenNumber + tokenNumber = tokenStore.size(); + + // fill map tokenInfo with addresses of tokens and 0's for owner Processes + typename std::list< Token >::iterator i; + for( i = tokenStore.begin(); i != tokenStore.end(); ++i ) + { + tokenInfo.insert( std::make_pair( &(*i), static_cast< base::Process* >(0) ) ); + } + + ODEMX_TRACE << this->log( "create" ).scope( typeid(ResTBase<Token>) ); + + statistics << this->param( "queue", acquireWait.getLabel() ).scope( typeid(ResTBase<Token>) ); + statistics << this->param( "initial tokens", tokenStore.size() ).scope( typeid(ResTBase<Token>) ); + statistics << this->param( "initial token limit", tokenLimit ).scope( typeid(ResTBase<Token>) ); + statistics << this->update( "tokens", tokenNumber ).scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, Create(this)); +} + +template < typename Token > +ResTBase< Token >::~ResTBase() +{ + ODEMX_TRACE << this->log( "destroy" ).scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, Destroy(this)); +} + +template < typename Token > +void ResTBase< Token >::release( Token* t ) +{ + // put free resource into a vector + std::vector< TokenType* > vec; + vec.push_back( t ); + + // handle that with release() below + return release( vec ); +} + +template < typename Token > +void ResTBase< Token >::release( std::vector< TokenType* >& releaseVec ) +{ + base::Process* currentProcess = getCurrentProcess(); + std::size_t n = releaseVec.size(); + + // for each released resource, update the tokenInfo map + typename std::vector< Token* >::iterator released; + typename std::map< Token*, base::Process* >::iterator stored; + + std::size_t countedReleases = 0; + for( released = releaseVec.begin(); released != releaseVec.end(); ++released ) + { + // try to get iterator to released token in tokenInfo + stored = tokenInfo.find( *released ); + + // check if the iterator is valid and whether + // the currentProcess Process really owns that resource + if( stored != tokenInfo.end() && stored->second == currentProcess ) + { + // released resource found, set the resource user to 0 + stored->second = static_cast< base::Process* >(0); + ++countedReleases; + continue; + } + + if( stored == tokenInfo.end() ) + { + error << this->log( "ResTBase::release(): token not found in token info" ) + .scope( typeid(ResTBase<Token>) ); + } + else if( stored->second != currentProcess ) + { + error << this->log( "ResTBase::release(): token returned by wrong user" ) + .scope( typeid(ResTBase<Token>) ); + } + } + + ODEMX_TRACE << this->log( "change token number" ) + .valueChange( tokenNumber, tokenNumber + countedReleases ) + .scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_ATTR_T(ResTBaseObserver<Token>, TokenNumber, tokenNumber, tokenNumber+countedReleases); + + // release token + tokenNumber += countedReleases; + + // check for failure + if ( countedReleases < n ) + { + warning << this->log( "ResTBase::release(): could not release all tokens" ) + .scope( typeid(ResTBase<Token>) ); + + ODEMX_TRACE << this->log( "release failed" ) + .detail( "partner", getPartner() ) + .detail( "released tokens", n - countedReleases ) + .scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, ReleaseFail(this, n - countedReleases)); + } + + ODEMX_TRACE << this->log( "release succeeded") + .detail( "partner", getPartner() ) + .detail( "released tokens", countedReleases ) + .scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, ReleaseSucceed(this, countedReleases)); + + statistics << this->count( "providers" ).scope( typeid(ResTBase<Token>) ); + statistics << this->update( "tokens", tokenNumber ).scope( typeid(ResTBase<Token>) ); + + // wake up waiting process objects + awakeFirst( &acquireWait ); +} + +template < typename Token > +void ResTBase< Token >::transfer( Token* t, base::Process* oldOwner, + base::Process* newOwner ) +{ + std::vector< Token* > v; + v.push_back( t ); + return transfer( v, oldOwner, newOwner ); +} + +template < typename Token > +void ResTBase< Token >::transfer( std::vector< Token* >& v, + base::Process* oldOwner, base::Process* newOwner ) +{ + assert( oldOwner ); + assert( newOwner ); + + typename std::vector< Token* >::iterator transferToken; + typename std::map< Token*, base::Process* >::iterator found; + + std::size_t transferCount = 0; + + // set a new owner for the given tokens + for( transferToken = v.begin(); transferToken != v.end(); ++transferToken ) + { + found = tokenInfo.find( *transferToken ); + + // token not found ? + if( found == tokenInfo.end() ) + { + error << this->log( "ResTBase::transfer(): transfer token not found in token info" ) + .scope( typeid(ResTBase<Token>) ); + continue; + } + + // correct owner ? + if( found->second == oldOwner ) + { + found->second = newOwner; + ++transferCount; + } + else // oldOwner is different from owner stored in tokenInfo + { + error << this->log( "ResTBase::transfer(): transfer token owned by another Process" ) + .scope( typeid(ResTBase<Token>) ); + } + } + + ODEMX_TRACE << this->log( "transfer" ) + .detail( "amount", transferCount ) + .detail( "old owner", oldOwner->getLabel() ) + .detail( "new owner", newOwner->getLabel() ) + .scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, Transfer(this, transferCount, oldOwner, newOwner)); +} + +template < typename Token > +void ResTBase< Token >::control( Token t ) +{ + ODEMX_TRACE << this->log( "add tokens" ) + .detail( "amount", 1 ).scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, Control(this, 1)); + + // increase max by one + ++tokenLimit; + + // add token to tokenStore and tokenInfo + tokenStore.push_back( t ); + tokenInfo.insert( std::make_pair( &(tokenStore.back()), static_cast< base::Process* >(0) ) ); + ++tokenNumber; + + // wake up waiting process objects + awakeFirst( &acquireWait ); +} + +template < typename Token > +void ResTBase< Token >::control( typename ResTBase< Token >::TokenVec& addVec ) +{ + std::size_t n = addVec.size(); + + ODEMX_TRACE << this->log( "add tokens" ) + .detail( "amount", n ).scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, Control(this, n)); + + // increase by number of added tokens + tokenLimit += n; + + // fill tokenStore and tokenInfo with tokens from addVec + // as long as the tokenLimit is not reached yet + typename std::vector< Token >::iterator i; + for( i = addVec.begin(); + i != addVec.end() && tokenStore.size() < tokenLimit; + ++i ) + { + tokenStore.push_back( *i ); + tokenInfo.insert( std::make_pair( &(tokenStore.back()), static_cast< base::Process* >(0) ) ); + ++tokenNumber; + } + + // wake up waiting process objects + awakeFirst( &acquireWait ); +} + +template < typename Token > +std::vector< Token > ResTBase< Token >::unControl( std::size_t n /* = 1 */) +{ + if( n > tokenStore.size() ) + { + error << this->log( "ResTBase::unControl(): attempt to remove more than max tokens" ) + .scope( typeid(ResTBase<Token>) ); + return std::vector< Token >(); + } + + if( ! getCurrentSched() || + getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << this->log( "ResTBase::unControl(): called by non-Process object" ) + .scope( typeid(ResTBase<Token>) ); + return std::vector< Token >(); + } + + ODEMX_TRACE << this->log( "remove tokens" ) + .detail( "amount", n ).scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_T(ResTBaseObserver<Token>, UnControl(this, n)); + + base::Process* currentProcess = getCurrentProcess(); + + // acquire enough token + // compute order of service + acquireWait.inSort( currentProcess ); + + if( n > tokenNumber || + acquireWait.getTop() != currentProcess ) + { + // not enough tokens or not the first process in queue + + // block execution + while( n > tokenNumber || + acquireWait.getTop() != currentProcess ) + { + currentProcess->sleep(); + + // handle interrupt + if( currentProcess->isInterrupted() ) + { + acquireWait.remove( currentProcess ); + return std::vector< Token >(); + } + } + + // block released + } + + ODEMX_TRACE << this->log( "change token number" ) + .valueChange( tokenNumber, tokenNumber - n ) + .scope( typeid(ResTBase<Token>) ); + + // observer + ODEMX_OBS_ATTR_T(ResTBaseObserver<Token>, TokenNumber, tokenNumber, tokenNumber-n); + + // fill return vector with the uncontrolled token objects + typename std::map< Token*, base::Process* >::iterator tInfo = tokenInfo.begin(); + std::vector< Token > unControlTokens; + + std::size_t acquired = 0; + while( tInfo != tokenInfo.end() && acquired < n ) + { + if( tInfo->second == 0 ) + { + unControlTokens.push_back( *(tInfo->first) ); + ++acquired; + + // remove the uncontrolled token from store + tokenStore.remove( *(tInfo->first) ); + + // remove the uncontrolled token from managing info map + // by using a copy of the non-incremented iterator returned by op++ + tokenInfo.erase( tInfo++ ); + } + else + { + ++tInfo; + } + } + + // acquire token + tokenNumber -= acquired; + + // adjust token limit + tokenLimit -= acquired; + + // remove process from queue + acquireWait.remove( currentProcess ); + + // awake next waiting process + awakeFirst( &acquireWait ); + + // return tokens + return unControlTokens; +} + + +template < typename Token > +std::size_t ResTBase< Token >::getTokenNumber() const +{ + return tokenNumber; +} + +template < typename Token > +std::size_t ResTBase< Token >::getTokenLimit() const +{ + return tokenLimit; +} + +template < typename Token > +const std::map< Token*, base::Process* >& ResTBase< Token >::getTokenInfo() const +{ + return tokenInfo; +} + +template < typename Token > +const std::list< Token >& ResTBase< Token >::getTokenStore() const +{ + return tokenStore; +} + +template < typename Token > +const base::ProcessList& ResTBase< Token >::getWaitingProcesses() const +{ + return acquireWait.getList(); +} + +template < typename Token > +Queue* ResTBase< Token >::getAcquireWait() +{ + return &acquireWait; +} + +template < typename Token > +base::SimTime ResTBase< Token >::getCurrentTime() +{ + return data::Producer::getSimulation().getTime(); +} + +template < typename Token > +odemx::base::Process* ResTBase< Token >::getCurrentProcess() +{ + return data::Producer::getSimulation().getCurrentProcess(); +} + +template < typename Token > +odemx::base::Sched* ResTBase< Token >::getCurrentSched() +{ + return data::Producer::getSimulation().getCurrentSched(); +} + +template < typename Token > +const data::Label& ResTBase< Token >::getPartner() +{ + if( getSimulation().getCurrentSched() != 0 ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + + return getSimulation().getLabel(); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/include/odemx/synchronization/res/ResTBase.h b/odemx-lite/include/odemx/synchronization/res/ResTBase.h new file mode 100644 index 0000000000000000000000000000000000000000..dd0161e8335cba51bff86c7cf6305d52df563d9c --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/res/ResTBase.h @@ -0,0 +1,296 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ResTBase.h + + \author Ronald Kluth + + \date created at 2008/02/18 + + \brief Declaration of odemx::synchronization::ResTBase and observer + + \note This header file is not meant for inclusion, use + odemx/synchronization/ResTemplate.h instead. + + \sa ResTBase.cpp + + \since 2.1 +*/ + +#ifndef ODEMX_RES_T_BASE_INCLUDED +#define ODEMX_RES_T_BASE_INCLUDED + +#include <odemx/data/Producer.h> +#include <odemx/data/Observable.h> +#include <odemx/statistics/Accumulate.h> +#include <odemx/synchronization/Queue.h> + + +#include <set> +#include <map> + +namespace odemx { + +//forward declaration +namespace base { +class Process; +class Simulation; +} + +namespace synchronization { + +template < typename > class ResTBaseObserver; + +/** \class ResTBase + + \author Ronald Kluth + + \brief ResTBase is an abstract base class for resources holding + objects of type Token + + \note ResTBase supports Observation + \note ResTBase supports Trace + + \sa Res, ResT, ResTChoice + + ResTBase provides many functions needed in resource classes + for synchronizing Process objects. + + \since 2.1 +*/ +template < typename TokenT > +class ResTBase +: public data::Producer +, public data::Observable< ResTBaseObserver< TokenT > > +{ +public: + + using data::Producer::trace; + using data::Producer::debug; + using data::Producer::info; + using data::Producer::warning; + using data::Producer::error; + using data::Producer::fatal; + using data::Producer::statistics; + + typedef TokenT TokenType; + typedef std::vector< TokenType > TokenVec; + typedef std::map< TokenType*, base::Process* > TokenOwnerMap; + typedef std::list< TokenType > StorageType; + typedef ResTBaseObserver< TokenType > ObserverType; + + /** + \brief Construction for user-defined Simulation + \param s + pointer to simulation + \param l + label of ResT object + \param initialResources + vector containing the initial tokens of the resource + \param o + observer of ResT object + + \note The Token type must be copyable! The initial resources will + be copied into the internal token store of the object. + + \note The token limit is set by the size of the \c initialResources + vector. The change it, use control(), or unControl(). + */ + ResTBase( base::Simulation& sim, const data::Label& label, + TokenVec& initialResources, ObserverType* obs = 0 ); + + /// Destruction + virtual ~ResTBase(); + + /** + \name Token usage + + These functions provide access for resource usage by Processes. + Tokens can be requested and thus acquired when then are + available. When the tokens are not needed anymore, the owning + Process can release them. + + \note There are different ways to select tokens, + this base class only provides a declaration for acquire. + + \note Use the derived classes ResT or ResTChoice + @{ + */ + /** + \brief forces implementation of acquire + + Pure virtual function which must be implemented in + derived classes. + */ + virtual TokenType* acquire() = 0; + + /** + \brief release a token + + Returns a previously acquired token to the resource + */ + void release( TokenType* e ); + + /** + \brief release token + + Returns previously acquired tokens to the resource + */ + void release( std::vector< TokenType* >& s ); + + /** + \brief transfer control of an acquired token to \p newOwner + + The \p newOwner is registered as holder of token \p e, meaning + this info is changed in the internal token info map. + */ + void transfer( TokenType* t, base::Process* oldOwner, + base::Process* newOwner ); + + /** + \brief transfer control of acquired token to \p newOwner + + The \p newOwner is registered as holder of the tokens in \p s. + */ + void transfer( std::vector< TokenType* >& v, base::Process* oldOwner, + base::Process* newOwner); + + /** + \brief add token \p e to ressource + + Add token \p e to the managed token set. + */ + void control( TokenType t ); + + /** + \brief add token to ressource + + Add token to the managed token set. + */ + void control( TokenVec& addVec ); + + /** + \brief remove \p n token from ressource + + Remove token from the managed token set. If there are not enough + token left in the ressource, the current process is blocked. + */ + TokenVec unControl( std::size_t n = 1 ); + //@} + + /** \name ResT status information + + The following functions provide access to the ResT object's + status during a simulation. + + @{ + */ + /** + \brief get number of available token + + Get number of currently avaliable token in ressource + */ + std::size_t getTokenNumber() const; + + /** + \brief get number of managed token + + Get maximum number of tokens managed by this ressource + */ + std::size_t getTokenLimit() const; + + /** + \brief Get token map + + Get info about all tokens and their owning processes. + */ + const TokenOwnerMap& getTokenInfo() const; + + /// Get a reference to the stored tokens + const StorageType& getTokenStore() const; + + /// get list of blocked process objects + const std::list< base::Process* >& getWaitingProcesses() const; + //@} + +protected: + + /// current time + base::SimTime getCurrentTime(); + /// current process + base::Process* getCurrentProcess(); + /// current scheduled object + base::Sched* getCurrentSched(); + /// get pointer to queue of processes waiting in acquire + Queue* getAcquireWait(); + /// get label of the currently active context (process or sim) + const data::Label& getPartner(); + /// current number of tokens + std::size_t tokenNumber; + /// maximum number of tokens + std::size_t tokenLimit; + + /// token storage + StorageType tokenStore; + /// token management + TokenOwnerMap tokenInfo; + /// process management + Queue acquireWait; +}; + +/** \interface ResTBaseObserver + + \author Ronald Kluth + + \brief Observer for ResT specific events + + \sa ResT +*/ +template < typename Token > +class ResTBaseObserver +{ +public: + typedef ResTBase< Token > ResType; + + virtual ~ResTBaseObserver() {} + + /// Creation + virtual void onCreate(ResType* sender) {} + /// Destruction + virtual void onDestroy(ResType* sender) {} + + /// Failed attempt to release n token + virtual void onReleaseFail(ResType* sender, std::size_t n) {} + /// Release of n token + virtual void onReleaseSucceed(ResType* sender, std::size_t n) {} + /// Transfer of n token + virtual void onTransfer(ResType* sender, std::size_t n, + base::Process* oldOwner, base::Process* newOwner) {} + /// Add tokens + virtual void onControl(ResType* sender, std::size_t n) {} + /// Remove tokens + virtual void onUnControl(ResType* sender, std::size_t n) {} + /// Change of token number + virtual void onChangeTokenNumber(ResType* sender, + std::size_t oldTokenNumber, std::size_t newTokenNumber) {} +}; + +} } // namespace odemx::synchronization + +#endif /*ODEMX_RES_T_BASE_INCLUDED*/ + diff --git a/odemx-lite/include/odemx/synchronization/res/ResTChoice.cpp b/odemx-lite/include/odemx/synchronization/res/ResTChoice.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01de5ebae6b5af5ffeb8d04f913a8085c830ab26 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/res/ResTChoice.cpp @@ -0,0 +1,245 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ResTChoice.cpp + + \author Ronald Kluth + + \date created at 2008/02/18 + + \brief Implementation of odemx::sync::ResTChoice + + \sa ResTChoice.h + + \since 2.1 +*/ + +#include <odemx/synchronization/res/ResTChoice.h> +#include <odemx/base/Sched.h> +#include <odemx/base/Process.h> + +namespace odemx { +namespace synchronization { + +template < typename Token > +ResTChoice< Token >::ResTChoice( base::Simulation& sim, + const data::Label& label, + std::vector< Token >& initialResources, + ResTChoiceObserver< Token >* o /* = 0*/ ) +: ResTBase< Token >( sim, label, initialResources, o ), + data::Observable< ResTChoiceObserver< Token > >( o ) +{ + // observer + ODEMX_OBS_T(ResTChoiceObserver<Token>, Create(this)); +} + +template < typename Token > +ResTChoice<Token>::~ResTChoice() +{ + // observer + ODEMX_OBS_T(ResTChoiceObserver<Token>, Destroy(this)); +} + +template < typename Token > +Token* ResTChoice< Token >::acquire() +{ + error << this->log( "ResTChoice::acquire(): selection function required, use overload" ) + .scope( typeid(ResTChoice<Token>) ); + return 0; +} + +template < typename Token > +Token* ResTChoice< Token >::acquire( typename ResTChoice< Token >::Selection select ) +{ + std::vector< Token* > found = acquire( select, 1 ); + + if( ! found.empty() ) + { + return found.front(); + } + return 0; +} + +template < typename Token > +const std::vector< Token* > ResTChoice< Token >::acquire( + typename ResTChoice< Token >::Selection select, std::size_t n ) +{ + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + // error: resource handling only implemented for processes + error << this->log( "ResTChoice::acquire(): called by non-Process object" ) + .scope( typeid(ResTChoice<Token>) ); + return std::vector< Token* >(); + } + + if( n > ResTBase< Token >::tokenLimit ) + { + warning << this->log( "ResTChoice::acquire(): requesting more than max tokens will always block" ) + .scope( typeid(ResTChoice<Token>) ); + } + + base::Process* currentProcess = getCurrentProcess(); + base::SimTime waitTime = 0; + + // compute order of service + ResTBase< Token >::acquireWait.inSort( currentProcess ); + + // the return vector to be filled by getMatchingTokens() + std::vector< Token* > matches; + + if( ResTBase< Token >::acquireWait.getTop() != currentProcess || + ! getMatchingTokens( select, n, matches ) ) + { + // not enough matching tokens or + // not the first process in queue + + ODEMX_TRACE << this->log( "acquire failed" ) + .detail( "partner", currentProcess->getLabel() ) + .detail( "requested tokens", n ) + .scope( typeid(ResTChoice<Token>) ); + // observer + ODEMX_OBS_T(ResTChoiceObserver<Token>, AcquireFail(this, n)); + + // statistics + base::SimTime waitStart = getCurrentTime(); + + do + { + currentProcess->sleep(); + + // handle interrupt + if( currentProcess->isInterrupted() ) + { + ResTBase< Token >::acquireWait.remove( currentProcess ); + return std::vector< Token* >(); + } + } + while( ResTBase< Token >::acquireWait.getTop() != currentProcess || + ! getMatchingTokens( select, n, matches ) ); + + // block released + // statistics + waitTime = getCurrentTime() - waitStart; + } + + ODEMX_TRACE << this->log( "change token number" ).valueChange( ResTBase<Token>::tokenNumber, ResTBase<Token>::tokenNumber - n ) + .scope( typeid(ResTChoice<Token>) ); + + // observer + ODEMX_OBS_ATTR_T(ResTChoiceObserver<Token>, TokenNumber, ResTBase< Token >::tokenNumber, ResTBase< Token >::tokenNumber-n); + + // acquire token + ResTBase< Token >::tokenNumber -= n; + + // fill return vector with pointers to free resource objects + typename std::vector< Token* >::iterator i; + + for( i = matches.begin(); i != matches.end(); ++i ) + { + // store the current user of selected resources in ResTBase< Token >::tokenInfo + + if( ResTBase< Token >::tokenInfo[ *i ] == 0 ) + { + ResTBase< Token >::tokenInfo[ *i ] = currentProcess; + } + else + { + // this error should never happen + error << this->log( "ResTChoice::acquire(): selected token is owned by another Process" ) + .scope( typeid(ResTChoice<Token>) ); + } + } + + ODEMX_TRACE << this->log( "acquire succeeded" ) + .detail( "partner", currentProcess->getLabel() ) + .detail( "requested tokens", n ) + .scope( typeid(ResTChoice<Token>) ); + + // statistics + statistics << this->count( "users" ).scope( typeid(ResTChoice<Token>) ); + statistics << this->update( "tokens", ResTBase< Token >::tokenNumber ).scope( typeid(ResTChoice<Token>) ); + statistics << this->update( "wait time", waitTime ).scope( typeid(ResTChoice<Token>) ); + + // observer + ODEMX_OBS_T(ResTChoiceObserver<Token>, AcquireSucceed(this, n)); + + // remove process from queue + ResTBase< Token >::acquireWait.remove( currentProcess ); + + // awake next + awakeFirst( ResTBase< Token >::getAcquireWait() ); + + return matches; +} + +template < typename Token > +base::SimTime ResTChoice< Token >::getCurrentTime() +{ + return data::Producer::getSimulation().getTime(); +} + +template < typename Token > +base::Process* ResTChoice< Token >::getCurrentProcess() +{ + return data::Producer::getSimulation().getCurrentProcess(); +} + +template < typename Token > +base::Sched* ResTChoice< Token >::getCurrentSched() +{ + return data::Producer::getSimulation().getCurrentSched(); +} + +template < typename Token > +bool ResTChoice< Token >::getMatchingTokens( + typename ResTChoice< Token >::Selection select, + std::size_t n, std::vector< Token* >& result ) +{ + std::size_t count = 0; + result.clear(); + + // find matching tokens + typename std::map< Token*, base::Process* >::iterator i; + for( i = ResTBase< Token >::tokenInfo.begin(); i != ResTBase< Token >::tokenInfo.end(); ++i ) + { + // count all matches + if( select( getCurrentProcess(), i->first ) ) + { + count++; + + // store free matches in result vector + if( i->second == 0 ) + { + result.push_back( i->first ); + + if( result.size() == n ) + break; + } + } + } + + if( count < n ) + { + warning << this->log( "ResTChoice::getMatchingTokens(): too few matching tokens in resource, will always block" ) + .scope( typeid(ResTChoice<Token>) ); + } + + return result.size() == n; +} + +} } // namespace odemx::sync diff --git a/odemx-lite/include/odemx/synchronization/res/ResTChoice.h b/odemx-lite/include/odemx/synchronization/res/ResTChoice.h new file mode 100644 index 0000000000000000000000000000000000000000..34a46c285730d789e0da300b77517dee773c6657 --- /dev/null +++ b/odemx-lite/include/odemx/synchronization/res/ResTChoice.h @@ -0,0 +1,177 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002-2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ResTChoice.h + + \author Ronald Kluth + + \date created at 2008/02/18 + + \brief Declaration of odemx::synchronization::ResTChoice and observer + + \note This header file is not meant for inclusion, use + odemx/synchronization/ResTemplate.h instead. + + \sa ResTChoice.cpp + + \since 2.1 +*/ + +#ifndef ODEMX_RES_T_CHOICE_INCLUDED +#define ODEMX_RES_T_CHOICE_INCLUDED + +#include <odemx/synchronization/res/ResTBase.h> + +namespace odemx { +namespace synchronization { + +//forward declaration +template < typename Token > +class ResTChoiceObserver; + +/** \class ResTChoice + + \author Ronald Kluth + + \brief ResTChoice is an abstract base class for resources holding + objects of type Token + + ResTChoice is a resource class for synchronizing Process objects based + on the availability of selected resources. A process is blocked in + acquire() if not enough tokens matching the selection criteria + are available. It is reactivated when enough tokens are released + to the resource. If multiple process objects are waiting for + reactivation, process queue priority and FIFO-strategy are used to + choose the process. + + \note ResTChoice supports Observation + \note ResTChoice supports Trace + + \sa Res, ResT + + \since 2.1 +*/ +template < typename Token > +class ResTChoice: + public ResTBase< Token >, + public data::Observable< ResTChoiceObserver< Token > > +{ +public: + + using data::Producer::trace; + using data::Producer::debug; + using data::Producer::info; + using data::Producer::warning; + using data::Producer::error; + using data::Producer::fatal; + using data::Producer::statistics; + using data::Producer::log; + using data::Producer::param; + using data::Producer::count; + using data::Producer::update; + using data::Producer::reset; + + /// function type for coding selections + typedef bool( *Selection )( base::Process* owner, Token* t ); + + /** + * \copydoc ResTBase(Simulation*,Label,std::vector<Token>&,ResTBaseObserver<Token>*) + */ + ResTChoice( base::Simulation& sim, const data::Label& label, + std::vector< Token >& initialResources, + ResTChoiceObserver< Token >* o = 0 ); + + /// Destruction + virtual ~ResTChoice(); + + /** + \name Token usage + + These functions provade access for resource usage by Processes. + Tokens can be requested and thus acquired when then are + available. When the tokens are not needed anymore, the owning + Process can release them. + + @{ + */ + /** + \brief acquire a token + + Required implementation of acquire, will output an error + to + */ + virtual Token* acquire(); + + /** + \brief find and acquire a token + + If no token matching the Selection condition is available, + the current process is blocked + */ + Token* acquire( typename ResTChoice< Token >::Selection select ); + + /** + \brief find and acquire token + + If there are not enough tokens matching the Selection condition + available, the current process is blocked + */ + const std::vector< Token* > acquire( Selection select, std::size_t n ); + +private: + + /// current simulation time + base::SimTime getCurrentTime(); + + /// current process + base::Process* getCurrentProcess(); + + /// current scheduled object + base::Sched* getCurrentSched(); + + /// help method to find tokens matching the selection + bool getMatchingTokens( Selection select, std::size_t n, + std::vector< Token* >& result ); +}; + +/** \interface ResTChoiceObserver + + \author Ronald Kluth + + \brief Observer for ResTChoice-specific events + + \since 2.1 + + \sa ResT +*/ +template < typename Token > +class ResTChoiceObserver: public ResTBaseObserver< Token > { +public: + typedef typename ResTBaseObserver< Token >::ResType ResType; + + virtual ~ResTChoiceObserver() {} + + /// Failed attempt to acquire n token + virtual void onAcquireFail(ResType* sender, std::size_t n) {} + /// Successful attempt to acquire n token + virtual void onAcquireSucceed(ResType* sender, std::size_t n) {} +}; + +} } // namespace odemx::synchronization + +#endif /*ODEMX_RES_T_CHOICE_INCLUDED*/ diff --git a/odemx-lite/include/odemx/util/DeletePtr.h b/odemx-lite/include/odemx/util/DeletePtr.h new file mode 100644 index 0000000000000000000000000000000000000000..a5f08d1cbd6efe4e6dbf0a6a5491cd3310bf2d8a --- /dev/null +++ b/odemx-lite/include/odemx/util/DeletePtr.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file DeletePtr.h + * @author Ronald Kluth + * @date created at 2009/03/29 + * @brief Declaration and implementation of functor odemx::DeletePtr + * @since 3.0 + */ + +#ifndef ODEMX_UTIL_DELETEPTR_INCLUDED +#define ODEMX_UTIL_DELETEPTR_INCLUDED + +namespace odemx { + +/** + * @brief Delete pointers of any type + * @tparam PointerT type of the objects pointed to + * + * This functor can call delete on any kind of pointer. It is useful in + * for_each loops that delete containers with pointers to owned resources. + * Each pointer is checked for @c 0 before delete is called on it. + */ +template< typename PointerT > +struct DeletePtr +{ + void operator()( PointerT* p ) + { + if( p ) delete p; + } +}; + +} // namespace odemx + +#endif /* ODEMX_UTIL_DELETEPTR_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/Exceptions.h b/odemx-lite/include/odemx/util/Exceptions.h new file mode 100644 index 0000000000000000000000000000000000000000..c8ab8edfeacd3d6b9de235efcfaa69bb9b38de83 --- /dev/null +++ b/odemx-lite/include/odemx/util/Exceptions.h @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Exceptions.h + * @author Ronald Kluth + * @date created at 2009/03/29 + * @brief Declaration and implementation of ODEMx exceptions + * @since 3.0 + */ + +#ifndef ODEMX_EXCEPTIONS_INCLUDED +#define ODEMX_EXCEPTIONS_INCLUDED + +#include <stdexcept> +#include <string> + +namespace odemx { + +/** @brief Exception type for the scheduler + * @ingroup util + */ +class SchedulingException +: public std::runtime_error +{ +public: + SchedulingException( const std::string& description ); +}; + +/** @brief Exception type for reporting queueing problems + * @ingroup util + */ +class QueueingException +: public std::runtime_error +{ +public: + QueueingException( const std::string& description ); +}; + +/** @brief Exception type for data module problems + * @ingroup util + */ +class DataException +: public std::runtime_error +{ +public: + DataException( const std::string& description ); +}; + +/** @brief Exception type for problem of output components + * @ingroup util + */ +class DataOutputException +: public std::runtime_error +{ +public: + DataOutputException( const std::string& description ); +}; + +//-----------------------------------------------------------------------inlines + +inline SchedulingException::SchedulingException( const std::string& description ) +: runtime_error( description ) +{ +} + +inline QueueingException::QueueingException( const std::string& description ) +: runtime_error( description ) +{ +} + +inline DataException::DataException( const std::string& description ) +: runtime_error( description ) +{ +} + +inline DataOutputException::DataOutputException( const std::string& description ) +: runtime_error( description ) +{ +} + +} // namespace odemx + +#endif /* ODEMX_EXCEPTIONS_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/ListInSort.h b/odemx-lite/include/odemx/util/ListInSort.h new file mode 100644 index 0000000000000000000000000000000000000000..8ed07289dd4c4072b39f4755f181500e45732331 --- /dev/null +++ b/odemx-lite/include/odemx/util/ListInSort.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ListInSort.h + * @author Ronald Kluth + * @date created at 2007/11/08 + * @brief Declaration and Implementation of odemx::ListInSort + * @since 2.1 + */ + +#ifndef ODEMX_UTIL_LISTINSORT_INCLUDED +#define ODEMX_UTIL_LISTINSORT_INCLUDED + +#include <list> +#include <algorithm> + +namespace odemx { + +/** + \brief Function template for sorted insertion in std::list<> container + + \param list + reference to std::list<> container + + \param newElement + the element to be sorted into the given list + + \param cmp + the chosen comparison functor by which the list is ordered + + \param fifo + use FIFO or LIFO strategy + + ListInSort is used for insertion of Sched objects into a + std::list< Sched* > container by the ExecutionList. It is also + employed to sort a ProcessQueue of type std::list< Process* > + using a user-defined predicate as sorting criterion. + + \sa DefaultCmp, QPriorityCmp +*/ +template < typename ListElementType, typename ComparisonFunctorType > +typename std::list< ListElementType >::iterator +inline ListInSort( std::list< ListElementType >& l, + ListElementType newElement, + ComparisonFunctorType& cmp, + bool fifo = true ) +{ + // an iterator to store the position + // where the new element should be inserted + typename std::list< ListElementType >::iterator insertLocation; + + // according to fifo or lifo, the new element is inserted + // either at the end or at the beginning of the possible range + // the insert location is determined by standard algorithms + if( fifo ) + insertLocation = std::upper_bound( l.begin(), l.end(), newElement, cmp ); + else // lifo + insertLocation = std::lower_bound( l.begin(), l.end(), newElement, cmp ); + + // insert returns an iterator to the location + // where the new element was placed in the list + return l.insert( insertLocation, newElement ); +} + +} // namespace odemx + +#endif /* ODEMX_UTIL_LISTINSORT_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/StringConversion.h b/odemx-lite/include/odemx/util/StringConversion.h new file mode 100644 index 0000000000000000000000000000000000000000..3141032a11e7fb6513523f6036c4bfe80f3a0132 --- /dev/null +++ b/odemx-lite/include/odemx/util/StringConversion.h @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file StringConversion.h + * @author Ronald Kluth + * @date created at 2009/03/29 + * @brief Declaration and implementation of string helpers + * @since 3.0 + */ + +#ifndef ODEMX_UTIL_STRINGCONVERSION_INCLUDED +#define ODEMX_UTIL_STRINGCONVERSION_INCLUDED + +#include <sstream> +#include <string> + +namespace odemx { + +/** + * @brief Get a string representation of the given value + * @tparam T The type of the given value, automatically deduced by the compiler + * @param value Reference to the given value + * @return The converted string + * + * This function converts any streamable C++-type into a string. It uses an + * std::ostringstream to do the work. To make this function work with + * user-defined types, operator<<() must be implemented for the type. + */ +template < typename T > +inline std::string toString( const T& value ) +{ + std::ostringstream convert; + convert << value; + return convert.str(); +} + +} // namespace odemx::util + +#endif /* ODEMX_UTIL_STRINGCONVERSION_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/TypeNames.h b/odemx-lite/include/odemx/util/TypeNames.h new file mode 100644 index 0000000000000000000000000000000000000000..6997afbcf104d5664d684a4df49176649c2f5ca6 --- /dev/null +++ b/odemx-lite/include/odemx/util/TypeNames.h @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TypeNames.h + * @author Ronald Kluth + * @date created at 2008/02/12 + * @brief Typedefs to retain backwards-compatibility after changing type names + * @since 2.1 + */ + +#ifndef ODEMX_TYPENAMES_INCLUDED +#define ODEMX_TYPENAMES_INCLUDED + +#include <odemx/odemx.h> + +// for this file to work without inclusion of <odemx/odemx.h> +// the necessary library headers must be included here: + +/* +#include <odemx/protocol/ProtocolStack.h> +#include <odemx/random/DiscreteDist.h> +#include <odemx/random/ContinuousDist.h> +#include <odemx/synchronization/CondQ.h> +#include <odemx/synchronization/Memory.h> +#include <odemx/synchronization/WaitQ.h> +#include <odemx/util/Table.h> +*/ + +namespace odemx +{ + typedef random::DiscreteDist Idist; + typedef random::DiscreteConst Iconst; + typedef random::ContinuousDist Rdist; + typedef random::ContinuousConst Rconst; + typedef random::NegativeExponential Negexp; + typedef random::RandomInt Randint; + typedef synchronization::CondQ Condq; + typedef synchronization::WaitQ Waitq; + typedef synchronization::Memory Memo; +} + +#endif /* ODEMX_TYPENAMES_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/TypeToString.h b/odemx-lite/include/odemx/util/TypeToString.h new file mode 100644 index 0000000000000000000000000000000000000000..873972c4adae71199872df1763187b5f74116adc --- /dev/null +++ b/odemx-lite/include/odemx/util/TypeToString.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file util/TypeToString.h + * @author Ronald Kluth + * @date created at 2009/03/29 + * @brief Declaration and implementation of odemx::typeToString() + * @since 3.0 + */ + +#ifndef ODEMX_UTIL_TYPETOSTRING_INCLUDED +#define ODEMX_UTIL_TYPETOSTRING_INCLUDED + +#include <CppLog/detail/TypeToString.h> + +namespace odemx { + +/** + * @brief Get a string representation of the type name + * @param type reference to a type_info object returned by typeid() + * @return the type name as string + * + * The function type_info::name() returns a mangled type name on GCC + * and thus needs to be treated differently than on other compilers. + * This function applies demangling to retrieve a human-readable + * string representation of type names. + */ +inline std::string typeToString( const std::type_info& type ) +{ + return Log::Detail::typeToString( type ); +} + +} // namespace odemx + +#endif /* ODEMX_UTIL_TYPETOSTRING_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/Version.h b/odemx-lite/include/odemx/util/Version.h new file mode 100644 index 0000000000000000000000000000000000000000..b7377a5ea07327b0c54ea84b7dbc06eb93b589fe --- /dev/null +++ b/odemx-lite/include/odemx/util/Version.h @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Version.h + * @author Ralf Gerstenberger + * @date created at 2003/06/10 + * @brief Declaration and Implementation of odemx::Version + * @sa Version.cpp + * @since 1.0 + */ + +#ifndef ODEMX_UTIL_VERSION_INCLUDED +#define ODEMX_UTIL_VERSION_INCLUDED + +#include <sstream> +#include <string> + +namespace odemx { + +/** + * @class Version + * @ingroup util + * @author Ralf Gerstenberger + * @brief ODEMx version information + * @since 1.0 + */ +class Version +{ +private: + /// The major version number + static const unsigned short major = 3; + /// The minor version number + static const unsigned short minor = 1; + +public: + /// Get major version number + static unsigned short getMajor() { return major; } + /// Get minor version number + static unsigned short getMinor() { return minor; } + /// Get version string + static const std::string getString() + { + static std::string version; + + if( version.empty() ) + { + std::ostringstream stream; + stream << getMajor() << '.' << getMinor(); + version = stream.str(); + } + return version; + } +}; + +} // namespace odemx + +#endif /* ODEMX_UTIL_VERSION_INCLUDED */ diff --git a/odemx-lite/include/odemx/util/attributes.h b/odemx-lite/include/odemx/util/attributes.h new file mode 100644 index 0000000000000000000000000000000000000000..282a5b12e9cad3d156ad853575ca933308aea759 --- /dev/null +++ b/odemx-lite/include/odemx/util/attributes.h @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file attributes.h + * @author Magnus Müller, Toralf Niebuhr + * @date created at 2011/04/15 + * @brief define compilier dependet attrtibutes + * @since 3.0 + */ + +#ifndef ATTRIBUTES_H +#define ATTRIBUTES_H + +#ifndef __has_attribute // Optional of course. + #define __has_attribute(x) 0 // Compatibility with non-clang compilers. +#endif + + +#ifdef __GNUC__ +#define DEPRECATED(func) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED(func) __declspec(deprecated) func +#elif __has_attribute(deprecated) +#define DEPRECATED(func) func __attribute__ ((deprecated)) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED(func) func +#endif + +#endif + diff --git a/odemx-lite/related documents/DA - Gerstenberger.pdf b/odemx-lite/related documents/DA - Gerstenberger.pdf new file mode 100644 index 0000000000000000000000000000000000000000..579c6618d44fc7dfef605e9b222ae4e0f2b82a33 Binary files /dev/null and b/odemx-lite/related documents/DA - Gerstenberger.pdf differ diff --git a/odemx-lite/related documents/DA - Hausding.pdf b/odemx-lite/related documents/DA - Hausding.pdf new file mode 100644 index 0000000000000000000000000000000000000000..75f4aa68862de81d5d828513c0407162a7dbee52 Binary files /dev/null and b/odemx-lite/related documents/DA - Hausding.pdf differ diff --git a/odemx-lite/related documents/DA - Kluth.pdf b/odemx-lite/related documents/DA - Kluth.pdf new file mode 100644 index 0000000000000000000000000000000000000000..02a9edb2b54a8badb210e6641bba29d182588b6f Binary files /dev/null and b/odemx-lite/related documents/DA - Kluth.pdf differ diff --git a/odemx-lite/related documents/SA - Integration von C++11-Features.pdf b/odemx-lite/related documents/SA - Integration von C++11-Features.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a11df63362c22023916132c2b2a9e553392bd06d Binary files /dev/null and b/odemx-lite/related documents/SA - Integration von C++11-Features.pdf differ diff --git a/odemx-lite/related documents/SA - Kluth.pdf b/odemx-lite/related documents/SA - Kluth.pdf new file mode 100644 index 0000000000000000000000000000000000000000..20fe1accceb9ab4379ca6cd7b0cefbd0182f8616 Binary files /dev/null and b/odemx-lite/related documents/SA - Kluth.pdf differ diff --git a/odemx-lite/related documents/SA - Morozova.pdf b/odemx-lite/related documents/SA - Morozova.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ba98573db376c6b8e8c10d7ae992cf0f532c93a1 Binary files /dev/null and b/odemx-lite/related documents/SA - Morozova.pdf differ diff --git a/odemx-lite/related documents/SA - Serialisierung von ODEMx-Simulationsmodellen.pdf b/odemx-lite/related documents/SA - Serialisierung von ODEMx-Simulationsmodellen.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f145418f8340b36c32a004bbc2a468f78f469be7 Binary files /dev/null and b/odemx-lite/related documents/SA - Serialisierung von ODEMx-Simulationsmodellen.pdf differ diff --git a/odemx-lite/related documents/WA - Schlue - Kontrollvariablen.pdf b/odemx-lite/related documents/WA - Schlue - Kontrollvariablen.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f80a07fe5a5beedfe82b40bc99632f769f9029f9 Binary files /dev/null and b/odemx-lite/related documents/WA - Schlue - Kontrollvariablen.pdf differ diff --git a/odemx-lite/src/base/Comparators.cpp b/odemx-lite/src/base/Comparators.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8bd7951a7eceb4e43a3bb2d273f85b59021b3efa --- /dev/null +++ b/odemx-lite/src/base/Comparators.cpp @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Comparators.cpp + * @author Ronald Kluth + * @date created at 2009/02/23 + * @brief Implementation of odemx::base::DefaultCmp and odemx::base::QPriorityCmp + * @sa Comparators.h + * @since 3.0 + */ + +#include <odemx/base/Comparators.h> +#include <odemx/base/Process.h> +#include <odemx/base/Sched.h> // Sched op< + +namespace odemx { +namespace base { + +bool DefaultCmp::operator()( const Sched* s1, const Sched* s2 ) const +{ + return s1->getPriority() > s2->getPriority(); +} + +bool QPriorityCmp::operator()( const Process* p1, const Process* p2 ) const +{ + return p1->getQueuePriority() > p2->getQueuePriority(); +} + +// comparison functor definition, needed for ExecutionList::inSort() +DefaultCmp defCmp; + +// comparison functor definition, needed for ProcessQueue::inSort() +QPriorityCmp qPrioCmp; + +} } // namespace odemx::base diff --git a/odemx-lite/src/base/Continuous.cpp b/odemx-lite/src/base/Continuous.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94305a1cb882552dc5d6dbbfb4c4bdafadcbd4f2 --- /dev/null +++ b/odemx-lite/src/base/Continuous.cpp @@ -0,0 +1,550 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file base/Continuous.cpp + * @author Ralf Gerstenberger + * @date created at 2003/06/15 + * @brief Implementation of odemx::base::Continuous + * @sa Continuous.h + * @since 1.0 + */ + +#include <odemx/base/Continuous.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <fstream> +#include <iostream> +#include <iomanip> +#include <cmath> +#include <cassert> + +namespace odemx { +namespace base { + +Continuous::Continuous( Simulation& sim, const data::Label& label, int dimension, + ContinuousObserver* obs ) +: Process( sim, label, obs ) +, data::Observable< ContinuousObserver >( obs ) +, state( dimension ) +, rate( dimension ) +, error_vector( dimension ) +, initial_state( dimension ) +, slope_1( dimension ) +, slope_2( dimension ) +, slope_3( dimension ) +, dimension( dimension ) +, stepLength( 0.01 ) +, minStepLength( 0.01 ) +, maxStepLength( 0.1 ) +, relative( 0 ) +, errorLimit( 0.1 ) +, stopped( 0 ) +, stopTime( HUGE_VAL ) +, stopCond( 0 ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, Create(this)); +} + + +Continuous::~Continuous() +{ + ODEMX_TRACE << log( "destroy" ); +} + +unsigned int Continuous::getDimension() const +{ + return dimension; +} + +void Continuous::interrupt() +{ + // stop integration + stopped = 2; + + Process::interrupt(); +} + +void Continuous::setStepLength(double min, double max) +{ + if( ( min <= 0 ) || ( max <= 0 ) || ( min >= max ) ) + { + error << log( "Continuous::setStepLength(): invalid step length boundaries" ) + .scope( typeid(Continuous) ); + + if( min < 0 ) min = -min; + if( max < 0 ) max = -max; + if( min == 0 ) min = 0.01; + if( max == 0 ) max = 0.1; + if( min >= max) max *= 10.0; + } + + minStepLength = min; + maxStepLength = max; +} + +double Continuous::getStepLength() const +{ + return stepLength; +} + +void Continuous::setErrorlimit( int type, double limit ) +{ + relative = type; + errorLimit = limit; +} + +void Continuous::addPeer( Process* newPeer ) +{ + assert( newPeer ); + + peers.push_back( newPeer ); + + ODEMX_TRACE << log( "add peer" ).detail( "process", newPeer ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, AddPeer(this, newPeer)); +} + +void Continuous::delPeer( Process* peer ) +{ + assert( peer ); + + peers.remove( peer ); + + ODEMX_TRACE << log( "remove peer" ).detail( "process", peer ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, RemovePeer(this, peer)); +} + +int Continuous::integrate( SimTime timeEvent, Condition stateEvent ) +{ + if( getProcessState() != Process::CURRENT ) + { + error << log( "Continuous::integrate(): object is not the current process" ) + .scope( typeid(Continuous) ); + } + + ODEMX_TRACE << log( "begin integrate" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, BeginIntegrate(this)); + + // initialise stop condition + stopTime = timeEvent; + if( stopTime == 0 ) + { + stopTime = HUGE_VAL; + } + stopCond = stateEvent; + + stopped = 0; + stepLength = maxStepLength; + time = getTime(); + + // reduce priority + setPriority( getPriority() - 1 ); + + while( ! stopIntegrate() + && getTime() < stopTime + && ! stopped ) + { + // save initial state + initial_state = state; + + // set step length + if( stepLength > maxStepLength ) + { + stepLength = maxStepLength; + } + + // synchronise with timeEvent + SimTime stepTime = getTime() + stepLength; + if( stepTime > stopTime ) + { + stepLength = stopTime - stepTime; + stepTime = stopTime; + } + + // synchronise with peers (reduce stepLength) + ProcessList::iterator i; + for( i = peers.begin(); i != peers.end(); ++i ) + { + Process* p = *i; + if( p->getProcessState() == Process::RUNNABLE ) + { + SimTime et = p->getExecutionTime(); + if( stepTime > et ) + { + stepTime = et; + } + } + + if ( stepTime < getTime() ) { + error << log( "Continuous::integrate(): stepTime is less than current time. Setting to current time." ) + .scope( typeid (Continuous) ); + stepTime = getTime(); + } + } + stepLength = stepTime - getTime(); + + // integrate + takeAStep(stepLength); + + // handle integration errors + while( reduce() ) + { + // while integration error to great: + + // reduce stepLength + stepLength /= 2.0; + + // reset state + state = initial_state; + + // try again + takeAStep( stepLength ); + } + + // handle state events + if( stopIntegrate() ) + { + // state event->Binary search for event time + binSearch(); + } + else + { + // waiting time + time += stepLength; + holdFor( stepLength ); + + ODEMX_TRACE << log( "new valid state" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, NewValidState(this)); + + // try to increase stepLength + stepLength *= 2.0; + } + } // end main while loop + + // reset priority + setPriority( getPriority() + 1 ); + + ODEMX_TRACE << log( "end integrate" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, EndIntegrate(this, stopped)); + + return stopped; +} + +void Continuous::binSearch() +{ + // Binary search (BS) + double sl = stepLength / 2.0; // step length for BS + + if( sl < minStepLength ) + { + // step length already to small + //->accept results + stopped = 1; + + // waiting time + time += stepLength; + holdFor( stepLength ); + + ODEMX_TRACE << log( "new valid state" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, NewValidState(this)); + } + else + { + state = initial_state; // reset state + while( sl >= minStepLength ) + { + // integrate + takeAStep( sl ); + + if( stopIntegrate() ) + { + // step length still to long + // reduce sl and try again + sl /= 2.0; + + // reset state + state = initial_state; + } + else + { + // accept step + time += sl; + holdFor( sl ); + + ODEMX_TRACE << log( "new valid state" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, NewValidState(this)); + + initial_state = state; + + // and try to get closer to the state event + sl /= 2.0; + + } + } + // final steps if conditions not reached + // take several minimal steps until condition reached + sl = minStepLength; + while (!stopIntegrate()){ + takeAStep( sl ); + time += sl; + holdFor( sl ); + ODEMX_TRACE << log( "new valid state" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, NewValidState(this)); + + initial_state = state; + } + stopped = 1; + } +} + +double Continuous::errorNorm() +{ + unsigned int i; + double keep_value = 0.0; + + for( i = 0; i <= getDimension() - 1; i++ ) + { + if( error_vector[i] > keep_value ) + { + keep_value = error_vector[i]; + } + } + + return keep_value; +} + +int Continuous::reduce() +{ + error_value = errorNorm(); + + if( error_value <= errorLimit ) + { + return 0; + } + else + { + if( stepLength < ( 2.0 * minStepLength ) ) + { + error << log( "Continuous::reduce(): error over limit, but can't reduce step length further" ) + .scope( typeid(Continuous) ); + + return 0; + } + else + { + return 1; + } + } + return 0; +} + +void Continuous::takeAStep( double h ) +{ + double hdiv2, hdiv3, hdiv6, hdiv8; + int i; + int n = getDimension() - 1; + hdiv2 = h / 2.0; + hdiv3 = h / 3.0; + hdiv6 = h / 6.0; + hdiv8 = h / 8.0; + + derivatives( time ); + for( i = 0; i <= n; i++ ) + { + slope_1[i] = rate[i]; + state[i] = initial_state[i] + hdiv3 * slope_1[i]; + } + + derivatives( time + hdiv3 ); + for( i = 0; i <= n; i++ ) + { + slope_2[i] = rate[i]; + state[i] = initial_state[i] + hdiv6 * ( slope_1[i] + slope_2[i] ); + } + + derivatives( time + hdiv3 ); + for( i = 0; i <= n; i++ ) + { + slope_2[i] = rate[i]; + state[i] = initial_state[i] + hdiv8 * ( slope_1[i] + 3.0 * slope_2[i] ); + } + + derivatives( time + hdiv2 ); + for( i = 0; i <= n; i++ ) + { + slope_3[i] = rate[i]; + state[i] = initial_state[i] + hdiv2 * ( slope_1[i] - 3.0 * slope_2[i] + 4.0 * slope_3[i] ); + error_vector[i]= state[i]; + } + + derivatives( time + h ); + for( i = 0; i <= n; i++ ) + { + slope_2[i] = rate[i]; + state[i] = initial_state[i] + hdiv6 * ( slope_1[i] + 4.0 * slope_3[i] + slope_2[i] ); + + if( relative ) + { + if( error_vector[i] ) + { + error_vector[i] = fabs( 0.2 * ( 1.0 - state[i] / error_vector[i] ) ); + } + } + else + { + error_vector[i] = fabs( 0.2 * ( error_vector[i] - state[i] ) ); + } + } +} + +bool Continuous::stopIntegrate() +{ + bool result = false; + if( stopCond != 0 ) + { + result = stopCond(this); + } + + return result; +} + +//--------------------------------------------------------------------ContuTrace + +ContuTrace::ContuTrace( Continuous* contu, const std::string& fileName ) +: out( 0 ) +, firstTime( true ) +{ + if( contu != 0 ) + { + contu->data::Observable< ContinuousObserver >::addObserver( this ); + } + + if( ! fileName.empty() ) + { + openFile( fileName ); + } + else if( contu != 0 ) + { + std::string fn = contu->getLabel(); + fn += "_trace.txt"; + openFile( fn ); + } +} + +ContuTrace::~ContuTrace() +{ + if( out == 0 || out == &std::cout ) + { + return; + } + + static_cast< std::ofstream* >( out )->close(); + delete out; +} + +void ContuTrace::onNewValidState( Continuous* sender ) +{ + using namespace std; + + assert( sender != 0 ); + + unsigned int i = 0; + + if( firstTime ) + { + if( out == 0 ) + { + std::string fn = sender->getLabel(); + fn += "_trace.txt"; + openFile( fn ); + } + + *out << endl; + *out << setw(60) << "T R A C E F I L E F O R " << sender->getLabel() << endl << endl; + *out << setw(13) << "Time"; + *out << setw(13) << "Steplength"; + *out << setw(13) << "Error"; + + for( i = 0; i < sender->getDimension(); ++i ) + { + *out << setw(15) << "state[" << i << "]"; + } + + for( i = 0; i < sender->getDimension(); ++i ) + { + *out << setw(15) << "rate[" << i << "]"; + } + + *out << endl; + + firstTime=false; + } + + ( *out ).setf( std::ios::showpoint ); + ( *out ).setf( std::ios::fixed ); + *out << setw( 13 ) << setprecision( 7 ) << sender->getTime(); + *out << setw( 13 ) << setprecision( 7 ) << sender->getStepLength(); + *out << setw( 13 ) << setprecision( 7 ) << sender->error_value; + + for( i = 0; i < sender->getDimension(); i++ ) + { + *out << setw( 17 ) << setprecision( 7 ) << sender->state[ i ]; + } + + for( i = 0; i < sender->getDimension(); i++ ) + { + *out << setw(17) << setprecision(7) << sender->rate[i]; + } + + *out << endl; +} + +void ContuTrace::openFile( const std::string& fileName ) +{ + out = new std::ofstream( fileName.c_str() ); + if( out == 0 || !( *out ) ) + { + // Error: cannot open file + std::cerr << "ContuTrace::openFile(): cannot open file; sending output to stdout." << std::endl; + out = &std::cout; + } +} + +} } // namespace odemx::base + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/DefaultSimulation.cpp b/odemx-lite/src/base/DefaultSimulation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0ba903d22755c8571894658bf6866d8eddc48fe --- /dev/null +++ b/odemx-lite/src/base/DefaultSimulation.cpp @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file DefaultSimulation.cpp + * @author Ronald Kluth + * @date created at 2009/02/07 + * @brief Implementation of odemx::base::DefaultSimulation + * @sa DefaultSimulation.h, Simulation.h, Simulation.cpp + * @since 3.0 + */ + +#include <odemx/base/DefaultSimulation.h> + +namespace odemx { +namespace base { + +//------------------------------------------------------construction/destruction + +DefaultSimulation::DefaultSimulation() +: Simulation( "DefaultSimulation" ) +{ +} + +DefaultSimulation::~DefaultSimulation() +{ +} + +//----------------------------------------------------------------initialization + +void DefaultSimulation::initSimulation() +{ +} + +} // namespace base + +//-----------------------------------------------------default simulation access + +base::Simulation& getDefaultSimulation() +{ + static base::DefaultSimulation defaultSim; + return defaultSim; +} + +} // namespace odemx diff --git a/odemx-lite/src/base/Event.cpp b/odemx-lite/src/base/Event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fba4af18117f448d1ed2a8930f3f9320bf017bb --- /dev/null +++ b/odemx-lite/src/base/Event.cpp @@ -0,0 +1,274 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Event.cpp + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Implementation of odemx::base::Event + * @sa Event.h + * @since 2.0 + */ + +#include <odemx/base/Event.h> +#include <odemx/base/DefaultSimulation.h> +#include <odemx/base/Simulation.h> +#include <odemx/util/Exceptions.h> + +#include <string> +#include <cassert> + +namespace odemx { +namespace base { + +//------------------------------------------------------construction/destruction + +Event::Event( Simulation& sim, const data::Label& label, EventObserver* obs ) +: Sched( sim, label, EVENT ) +, data::Observable< EventObserver >( obs ) +, executionTime_( static_cast< SimTime >( 0 ) ) +, priority_( 0.0 ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Event) ); + + // observer + ODEMX_OBS(EventObserver, Create(this)); +} + +Event::~Event () +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Event) ); +} + +//----------------------------------------------------------------execution time + +SimTime Event::getExecutionTime() const +{ + return executionTime_; +} + +SimTime Event::setExecutionTime( SimTime newTime ) +{ + assert(newTime >= getTime()); + SimTime oldTime = executionTime_; + executionTime_ = newTime; + + ODEMX_TRACE << log( "change execution time" ) + .valueChange( oldTime, newTime ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS_ATTR(EventObserver, ExecutionTime, oldTime, executionTime_); + + return oldTime; +} + +//--------------------------------------------------------------------scheduling + +void Event::schedule() +{ + ODEMX_TRACE << log( "schedule" ) + .detail( "partner", getPartner() ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, Schedule( this ) ); + + // scheduling + setExecutionTime( getTime() ); + getSimulation().getScheduler().insertSched( this ); +} + +void Event::scheduleIn( SimTime delay ) +{ + assert( ! (delay < 0) ); + + ODEMX_TRACE << log( "schedule in" ) + .detail( "current", getPartner() ) + .detail( "relative time", delay ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, ScheduleIn( this, delay ) ); + + // scheduling + setExecutionTime( getTime() + delay ); + getSimulation().getScheduler().insertSched( this ); +} + +void Event::scheduleAt( SimTime absoluteTime ) +{ + assert( ! (absoluteTime < getTime()) ); + + ODEMX_TRACE << log( "schedule at" ) + .detail( "current", getPartner() ) + .detail( "absolute time", absoluteTime ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, ScheduleAt( this, absoluteTime ) ); + + // scheduling + setExecutionTime( absoluteTime ); + getSimulation().getScheduler().insertSched( this ); +} + +void Event::scheduleAppend() +{ + ODEMX_TRACE << log( "schedule append" ) + .detail( "partner", getPartner() ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, ScheduleAppend( this ) ); + + // scheduling + setExecutionTime( getTime() ); + getSimulation().getScheduler().addSched( this ); +} + +void Event::scheduleAppendIn( SimTime delay ) +{ + assert( ! (delay < 0) ); + + ODEMX_TRACE << log( "schedule append in" ) + .detail( "current", getPartner() ) + .detail( "relative time", delay ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, ScheduleAppendIn( this, delay ) ); + + // scheduling + setExecutionTime( getTime() + delay ); + getSimulation().getScheduler().addSched( this ); +} + +void Event::scheduleAppendAt( SimTime absoluteTime ) +{ + assert( ! (absoluteTime < getTime()) ); + + ODEMX_TRACE << log( "schedule append at" ) + .detail( "current", getPartner() ) + .detail( "absolute time", absoluteTime ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, ScheduleAppendAt( this, absoluteTime ) ); + + // scheduling + setExecutionTime( absoluteTime ); + getSimulation().getScheduler().addSched( this ); +} + +void Event::removeFromSchedule() +{ + if( isScheduled() ) + { + getSimulation().getScheduler().removeSched( this ); + + ODEMX_TRACE << log( "remove from schedule" ) + .detail( "partner", getPartner() ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, RemoveFromSchedule( this ) ); + } + else + { + error << log( "Event::removeFromSchedule(): event is not scheduled" ) + .detail( "partner", getPartner() ) + .scope( typeid(Event) ); + } +} + +//---------------------------------------------------------------------execution + +void Event::execute() +{ + if( ! isScheduled() ) + { + // error: Event has to be scheduled to be executed + fatal << log( "Event::executeEvent(): event is not scheduled" ) + .scope( typeid(Event) ); + + throw SchedulingException( "Event not scheduled" ); + } + + // remove Event from ExecutionList + getSimulation().getScheduler().removeSched( this ); + + ODEMX_TRACE << log( "execute event" ).scope( typeid(Event) ); + + // observer + ODEMX_OBS( EventObserver, ExecuteEvent( this ) ); + + // current must be set here, the old value is needed for the trace above + getSimulation().setCurrentSched( this ); + + // execute the action represented by this Event + eventAction(); +} + +//----------------------------------------------------------------------priority + +Priority Event::setPriority( Priority newPriority ) +{ + Priority oldPriority = priority_; + priority_ = newPriority; + + ODEMX_TRACE << log( "change priority" ) + .valueChange( oldPriority, newPriority ) + .scope( typeid(Event) ); + + // observer + ODEMX_OBS_ATTR( EventObserver, Priority, oldPriority, newPriority ); + + if( isScheduled() ) + { + // setPriority() influences ExecutionList ordering + getSimulation().getScheduler().inSort( this ); + } + + return oldPriority; +} + +Priority Event::getPriority() const +{ + return priority_; +} + +//-----------------------------------------------------------------------helpers + +SimTime Event::getCurrentTime() +{ + warning << log( "Event::getCurrentTime(): This method is deprecated. Use Sched::getTime() instead" ).scope( typeid(Event) ); + return getTime(); +} + +const data::Label& Event::getPartner() +{ + if( getSimulation().getCurrentSched() != 0 ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + + return getSimulation().getLabel(); +} + +} } // namespace odemx::base diff --git a/odemx-lite/src/base/ExecutionList.cpp b/odemx-lite/src/base/ExecutionList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b36d1d5584bdda79bde47874d9bd666132db9b20 --- /dev/null +++ b/odemx-lite/src/base/ExecutionList.cpp @@ -0,0 +1,319 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ExecutionList.cpp + * @author Ralf Gerstenberger + * @date created at 2002/01/25 + * @brief Implementation of odemx::base::ExecutionList + * @sa ExecutionList.h + * @since 1.0 + */ + +#include <odemx/base/ExecutionList.h> +#include <odemx/base/Comparators.h> +#include <odemx/base/Event.h> +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +#include <odemx/util/ListInSort.h> + +#include <algorithm> +#include <cassert> +#include <iostream> +#include <iomanip> +#include <sstream> + +#ifdef _MSC_VER +#include <functional> +#else +#include <functional> +#endif + +namespace odemx { +namespace base { + +//------------------------------------------------------construction/destruction + +ExecutionList::ExecutionList( Simulation& sim, const data::Label& label ) +: data::Producer( sim, label ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(ExecutionList) ); +} + +ExecutionList::~ExecutionList() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(ExecutionList) ); +} + +//---------------------------------------------------------------sched insertion + +void ExecutionList::addSched( Sched* s ) +{ + assert( s ); + + ODEMX_TRACE << log( "add" ) + .detail( "partner", s->getLabel() ) + .scope( typeid(ExecutionList) ); + + // adjust execution time if necessary + if ( s->getExecutionTime() < getTime() ) + { + s->setExecutionTime( getTime() ); + } + + // append Sched s at its ExecutionTime + // to ExecutionList (FIFO), considering priority + inSort( s ); +} + +void ExecutionList::insertSched( Sched* s ) +{ + assert( s ); + + ODEMX_TRACE << log( "insert" ) + .detail( "partner", s->getLabel() ) + .scope( typeid(ExecutionList) ); + + // adjust execution time + if ( s->getExecutionTime() < getTime() ) + { + s->setExecutionTime( getTime() ); + } + + // insert Sched s at ExecutionTime in + // ExecutionList (LIFO), considering priority + inSort( s, false ); +} + +void ExecutionList::insertSchedAfter( Sched* s, Sched* partner ) +{ + assert( s && partner ); + + if( s == partner ) + { + error << log( "ExecutionList::insertSchedAfter(): " + "sched and partner are the same" ) + .scope( typeid(ExecutionList) ); + return; + } + + if( ! partner->isScheduled() ) + { + error << log( "ExecutionList::insertSchedAfter(): " + "partner not scheduled" ) + .scope( typeid(ExecutionList) ); + return; + } + + // remove Sched s from ExecutionList if scheduled + if( s->isScheduled() ) + { + removeSched( s ); + } + + Priority prevPrio = partner->getPriority(); + + // adjust priority so the list order remains correct for s and partner + if ( s->getPriority() > prevPrio ) + { + s->setPriority( prevPrio ); + } + + // set s to execution time of partner + s->setExecutionTime( partner->getExecutionTime() ); + + // insert Sched s after partner + SchedList::iterator pos = partner->execListIter_; + ++pos; + s->execListIter_ = partner->scheduleLoc_.second->insert( pos, s ); + s->scheduleLoc_ = partner->scheduleLoc_; + s->scheduled_ = true; + + ODEMX_TRACE << log( "insert after" ) + .detail( "partner", s->getLabel() ) + .detail( "after", partner->getLabel() ) + .scope( typeid(ExecutionList) ); +} + +void ExecutionList::insertSchedBefore( Sched* s, Sched* partner ) +{ + assert( s && partner ); + + if( s == partner ) + { + error << log( "ExecutionList::insertSchedBefore(): " + "sched and partner are the same" ) + .scope( typeid(ExecutionList) ); + return; + } + + if( ! partner->isScheduled() ) + { + error << log( "ExecutionList::insertSchedBefore(): " + "partner not scheduled" ) + .scope( typeid(ExecutionList) ); + return; + } + + // remove Sched s from ExecutionList if scheduled + if( s->isScheduled() ) + { + removeSched( s ); + } + + Priority partnerPrio = partner->getPriority(); + + // adjust priority to maintain list order + if ( s->getPriority() < partnerPrio ) + { + s->setPriority( partnerPrio ); + } + + // set s execution time to execution time of partner + s->setExecutionTime( partner->getExecutionTime() ); + + // insert Sched s before partner + assert( partner->scheduleLoc_.second ); + s->execListIter_ = partner->scheduleLoc_.second->insert( partner->execListIter_, s ); + s->scheduleLoc_ = partner->scheduleLoc_; + s->scheduled_ = true; + + ODEMX_TRACE << log( "insert before" ) + .detail( "partner", s->getLabel() ) + .detail( "before", partner->getLabel() ) + .scope( typeid(ExecutionList) ); +} + +void ExecutionList::inSort( Sched* s, bool fifo ) +{ + assert( s ); + + // remove the object from exec list if it is already scheduled + if ( s->isScheduled() ) + { + removeSched( s ); + } + + // insert s into ordered list and store the location as iterator + s->scheduleLoc_ = std::make_pair( s->getExecutionTime(), + &( schedule_[ s->getExecutionTime() ] ) ); + + s->execListIter_ = ListInSort< Sched*, DefaultCmp >( + *s->scheduleLoc_.second, s, defCmp, fifo ); + + s->scheduled_ = true; +} + +//-----------------------------------------------------------------sched removal + +void ExecutionList::removeSched( Sched* s ) +{ + assert( s ); + + if( ! s->isScheduled() ) + { + error << log( "ExecutionList::removeSched(): " + "attempt to remove unscheduled object" ) + .detail( "sched", s->getLabel() ) + .scope( typeid(ExecutionList) ); + return; + } + + // remove s from its schedule list + assert( s->scheduleLoc_.second ); + s->scheduleLoc_.second->erase( s->execListIter_ ); + + // erase the map entry from the list if no other object is scheduled at the time + if( s->scheduleLoc_.second->empty() ) + { + schedule_.erase( s->scheduleLoc_.first ); + } + + // reset members + s->scheduleLoc_ = std::make_pair( static_cast< SimTime >( 0 ), + static_cast< SchedList* >( 0 ) ); + s->scheduled_ = false; + + ODEMX_TRACE << log( "remove" ) + .detail( "sched", s->getLabel() ) + .scope( typeid(ExecutionList) ); +} + +//-------------------------------------------------------------various accessors + +Sched* ExecutionList::getNextSched() const +{ + if( schedule_.empty() ) + { + return 0; + } + return schedule_.begin()->second.front(); +} + +SimTime ExecutionList::getNextExecutionTime() const +{ + if( schedule_.empty() ) + { + return 0; + } + return schedule_.begin()->first; +} + +bool ExecutionList::isEmpty() const +{ + return schedule_.empty(); +} + +SimTime ExecutionList::getTime() +{ + return getSimulation().getTime(); +} + +//-----------------------------------------------------------------------logging + +void ExecutionList::logToChannel( const ChannelPtr channel ) const +{ + // create record + data::SimRecord record = log( "scheduled objects" ).scope( typeid(ExecutionList) ); + record.detail( "time entries", schedule_.size() ); + + // add record details ( Position, Time, Label ) + std::ostringstream tmpStream; + size_t position = 0; + + // iterate over the map + for( Schedule::const_iterator iter = schedule_.begin(); + iter != schedule_.end(); ++iter ) + { + // iterate over each list + for( SchedList::const_iterator listIter = iter->second.begin(); + listIter != iter->second.end(); ++listIter, ++position ) + { + Sched* scheduled = *listIter; + + record.detail( "pos", position ) + .detail( "time", scheduled->getExecutionTime() ) + .detail( "obj", scheduled->getLabel() ); + } + } + + // log the whole record to the given channel + channel << record; +} + +} } // namespace odemx::base diff --git a/odemx-lite/src/base/Process.cpp b/odemx-lite/src/base/Process.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0764c4a6e75708af383defc50b06ea960be469c --- /dev/null +++ b/odemx-lite/src/base/Process.cpp @@ -0,0 +1,1065 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Process.cpp + * @author Ralf Gerstenberger + * @date created at 2002/01/30 + * @brief Implementation of odemx::base::Process + * @sa Process.h + * @since 1.0 + */ + +#include <odemx/base/Process.h> +#include <odemx/base/Event.h> +#include <odemx/base/Simulation.h> +#include <odemx/synchronization/ProcessQueue.h> +#include <odemx/synchronization/Timer.h> +#include <odemx/synchronization/Memory.h> +#include <odemx/util/Exceptions.h> + +#include <odemx/base/control/Control.h> +#include <odemx/base/control/ControlBase.h> + +#include <string> +#include <memory> // auto_ptr + +#ifdef _MSC_VER +#include <functional> +#else +#include <functional> +#endif + + +namespace odemx { +namespace base { + +Process::Process( Simulation& sim, const data::Label& label, ProcessObserver* obs ) +: Sched( sim, label, PROCESS ) +, Coroutine( &sim, obs ) +, data::Observable< ProcessObserver >( obs ) +, processState_( CREATED ) +, priority_( 0.0 ) +, executionTime_( static_cast< SimTime >(0) ) +, validReturn_( false ) +, returnValue_( 0 ) +, queue_( 0 ) +, enqueueTime_( static_cast< SimTime >(0) ) +, dequeueTime_( static_cast< SimTime >(0) ) +, queuePriority_( 0.0 ) +, isInterrupted_( false ) +, interrupter_( 0 ) +, isAlerted_( false ) +, alerter_( 0 ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Create(this)); + + this->getSimulation().setProcessAsCreated( this ); +} + +Process::~Process() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Process) ); + + // the simulation must not have a pointer to a destroyed process + getSimulation().removeProcessFromList( this ); +} + +void Process::activate() +{ + ODEMX_TRACE << log( "activate" ).detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Activate(this)); + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // reset interrupt state + resetInterrupt(); + + // reset memory alert state + resetAlert(); + + // scheduling + setExecutionTime( getTime() ); + getSimulation().getScheduler().insertSched( this ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::activateIn( SimTime t ) +{ + if ( t < 0 ) { + error << log( "Process::activateIn(): Parameter t less than 0 not allowed. Setting it to 0." ) + .scope( typeid(Process) ); + t = 0; + } + + ODEMX_TRACE << log( "activate in" ) + .detail( "relative time", t ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, ActivateIn(this, t)); + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // reset interrupt state + resetInterrupt(); + + // reset Memory::alert state + resetAlert(); + + // scheduling + setExecutionTime( getTime() + t ); + getSimulation().getScheduler().insertSched( this ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::activateAt( SimTime t ) +{ + if ( t < getTime () ) { + error << log( "Process::activateAt(): Parameter t less than current time not allowed. Setting it to current time." ) + .scope( typeid(Process) ); + t = getTime(); + } + + ODEMX_TRACE << log( "activate at" ) + .detail( "absolute time", t ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, ActivateAt(this, t)); + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // reset interrupt state + resetInterrupt(); + + // reset Memory::alert state + resetAlert(); + + // scheduling + setExecutionTime( t ); + getSimulation().getScheduler().insertSched( this ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::activateBefore( Sched* p ) +{ + assert( p ); + + ODEMX_TRACE << log( "activate before" ) + .detail( "partner", getPartner() ) + .detail( "before", p-> getLabel() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, ActivateBefore(this, p)); + + // state management + if (!setProcessState(RUNNABLE)) + { + return; + } + + // reset interrupt state + resetInterrupt(); + + // reset Memory::alert state + resetAlert(); + + // scheduling + getSimulation().getScheduler().insertSchedBefore( this, p ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::activateAfter( Sched* p ) +{ + assert( p ); + + ODEMX_TRACE << log( "activate after" ) + .detail( "partner", getPartner() ) + .detail( "after", p->getLabel() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, ActivateAfter(this, p)); + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // reset interrupt state + resetInterrupt(); + + // reset Memory::alert state + resetAlert(); + + // scheduling + getSimulation().getScheduler().insertSchedAfter( this, p ); + + // continue simulation ? + // this function should never require a context change + // because scheduling after another Sched object requires + // for that to be executed first; + + // if compSimulation() is called here, it leads to odd + // stepping results because the caller of this function + // has to continue its life cycle anyway + + // an attempt to make this work with self-activation: + if( this == getCurrentSched() ) + { + getSimulation().switchTo(); + } +} + +void Process::genericHoldUntil(SimTime t) { + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // reset interrupt state + resetInterrupt(); + + // reset Memory::alert state + resetAlert(); + + // scheduling + setExecutionTime( t ); + getSimulation().getScheduler().addSched( this ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::hold() +{ + ODEMX_TRACE << log( "hold" ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Hold(this)); + genericHoldUntil(getTime()); +} + +void Process::holdFor( SimTime t ) +{ + if ( t < 0 ) { + error << log( "Process::holdFor(): Parameter t less than 0 not allowed. Setting it to 0." ) + .scope( typeid(Process) ); + t = 0; + } + + ODEMX_TRACE << log( "hold for" ).detail( "relative time", t ) + .detail( "partner", getPartner() ).scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, HoldFor(this, t)); + + genericHoldUntil(getTime() + t); +} + +void Process::holdUntil( SimTime t ) +{ + if ( t < getTime () ) { + error << log( "Process::activateAt(): Parameter t less than current time not allowed. Setting it to current time." ) + .scope( typeid(Process) ); + t = getTime(); + } + + ODEMX_TRACE << log( "hold until" ).detail( "absolute time", t ) + .detail( "partner", getPartner() ).scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, HoldUntil(this, t)); + + genericHoldUntil(t); + +} + +bool Process::waitUntil(const Condition& condition, const std::string label, + const std::vector<std::reference_wrapper<ControlBase>>& controls) +{ + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "Process::wait(): called by non-Process object" ) + .scope( typeid(Process) ) + .detail( "condition" , label); + return false; + } + + if (getCurrentProcess() != this) { + error << log( "Process::wait(): calling Process must be the current Process") + .scope( typeid(Process) ) + .detail( "condition" , label); + return false; + } + + // log + ODEMX_TRACE << log( "wait" ) + .scope( typeid(Process) ) + .detail( "condition" , label); + + resetAlert(); + + if(condition(this)) { + + // shortcut if condition(this) returned true + + // log + ODEMX_TRACE << log( "continue" ) + .scope( typeid(Process) ) + .detail( "condition turned true immediately" , label); + + // statistics + statistics << update( "wait time", 0 ).scope( typeid(Process) ); + + return true; + + } else { + + // condition(this) returned false + + // statistics + base::SimTime waitStart = getTime(); + + // create memory vector representing controls for observation + std::unique_ptr< synchronization::IMemoryVector > memoryVector( new synchronization::IMemoryVector ); + memoryVector->reserve(controls.size()); + + // register conditions and build memory vector + for(auto& control: controls) { + control.get().waitingProcesses_.push_back(this); + memoryVector->push_back(&control.get()); + } + + // observer + ODEMX_OBS(ProcessObserver, Wait(this, memoryVector.get())); + + // check condition and block + while( ! (isAlerted() || condition(this)) ) + { + this->sleep(); + + if( this->isInterrupted() ) + { + // unregister conditions + for(auto& control: controls) { + control.get().waitingProcesses_.remove(this); + } + return false; + } + } + + // block released + + // process observation is handled in alertProcess(), called by ControlBase::signal() + + // unregister this process + for(auto& control: controls) { + control.get().waitingProcesses_.remove(this); + } + + // log + ODEMX_TRACE << log( "continue" ) + .scope( typeid(Process) ) + .detail( "condition turned true" , label); + + // statistics + base::SimTime waitTime = getTime() - waitStart; + statistics << update( "wait time", waitTime ).scope( typeid(Process) ); + statistics << count( "users" ).scope( typeid(ControlBase) ); + + return true; + } +} + +// m0 always has to be given, else no matching call +synchronization::IMemory* Process::wait( synchronization::IMemory* m0, synchronization::IMemory* m1, + synchronization::IMemory* m2, synchronization::IMemory* m3, synchronization::IMemory* m4, synchronization::IMemory* m5 ) +{ + assert( m0 ); + + // TODO: implement this and the other overload with vector object, not ptr + // so the internally created MemoryVector is cleaned up automatically + std::unique_ptr< synchronization::IMemoryVector > memvec( new synchronization::IMemoryVector ); + + memvec->reserve( 6 ); + memvec->push_back( m0 ); + + // add more parameters to vector, if they are given + if( m1 ) memvec->push_back( m1 ); + if( m2 ) memvec->push_back( m2 ); + if( m3 ) memvec->push_back( m3 ); + if( m4 ) memvec->push_back( m4 ); + if( m5 ) memvec->push_back( m5 ); + + synchronization::IMemory* alerter = wait( memvec.get() ); + return alerter; +} + +synchronization::IMemory* Process::wait( synchronization::IMemoryVector* memvec ) +{ + assert( memvec ); + + if( memvec->empty() ) + { + warning << log( "Process::wait(): no memory objects given" ) + .scope( typeid(Process) ); + + return 0; + } + + traceWait( *memvec ); + + // observer + ODEMX_OBS( ProcessObserver, Wait( this, memvec ) ); + + // before suspending, check availability of memory objects + synchronization::IMemoryVector::iterator iter; + for( iter = memvec->begin(); iter != memvec->end(); ++iter ) + { + synchronization::IMemory* current = *iter; + + if ( current->isAvailable() ) + { + // log the available object + data::Producer* labeled = dynamic_cast< data::Producer* >( current ); + if( labeled != 0 ) + { + ODEMX_TRACE << log( "available" ).detail( "memory object", labeled->getLabel() ) + .scope( typeid(Process) ); + } + // memory object cannot be cast to labeled object, use address + else + { + ODEMX_TRACE << log( "available" ) + .detail( "memory object", "no label" ) + .scope( typeid(Process) ); + } + + // if a Timer is not set, do not return, it might be set elsewhere + if( current->getMemoryType() == synchronization::IMemory::TIMER ) + { + warning << log( "Process::wait(): unset timer available" ) + .detail( "memory object", static_cast< synchronization::Timer* >( current )->getLabel() ) + .scope( typeid(Process) ); + } + else // other available Memo objects will be returned + { + return current; + } + } + } + + // since none are available, register this process with the given Memory objects + for( iter = memvec->begin(); iter != memvec->end(); ++iter ) + { + (*iter)->remember( this ); + } + + // the alert mechanism is normally only used with wait() + // reset alerter and alerted anyway, if set somewhere else + resetAlert(); + + // suspend process + sleep(); + + // ************* beyond this point, the process was awakened ************ + + // trace of alert and interrupt in other methods + + // check for Memory alert + if( isAlerted() ) + { + synchronization::IMemory* currentAlerter = getAlerter(); + + for( iter = memvec->begin(); iter != memvec->end(); ++iter ) + { + // currentAlerter has already removed this process + // Note: We have to check if the process current process is really deleted + // from all waiting lists, as PortHeadT doesn't delete on alert. + + // we try to dynamic_cast to Memory*. If it is a Memory object, we know that we can + // use its processIsWaiting method. + if ( (*iter) != currentAlerter ) + { + (*iter)->forget( this ); + } + else + { + odemx::synchronization::Memory *memory = dynamic_cast< odemx::synchronization::Memory* > (*iter); + if ( memory && memory -> processIsWaiting ( *this ) ) + (*iter) -> forget ( this ); + } + } + + // reset so outdated alerted/alerter cannot be used elsewhere by accident + resetAlert(); + + return currentAlerter; + } + // the sleep() period can be interrupted by other processes + else if( isInterrupted() ) + { + // remove this from all Memos + for( iter = memvec->begin(); iter != memvec->end(); ++iter ) + { + (*iter)->forget( this ); + } + + warning << log( "Process::wait(): waiting period ended by interrupt" ) + .detail( "interrupter", getInterrupter()->getLabel() ) + .scope( typeid(Process) ); + + // when wait returns 0, a Process should check for interrupts + return 0; + } + else + { + error << log( "Process::wait(): Process awakened without alert or interrupt" ) + .scope( typeid(Process) ); + } + return 0; +} + +void Process::alertProcess( synchronization::IMemory* alerter ) +{ + assert( alerter ); + + // trace alert and alerter + data::Producer* labeled = dynamic_cast< data::Producer* >( alerter ); + if( labeled != 0 ) + { + ODEMX_TRACE << log( "alert" ) + .detail( "memory object", labeled->getLabel() ) + .scope( typeid(Process) ); + } + // memory object cannot be cast to labeled object, use address + else + { + ODEMX_TRACE << log( "alert" ) + .detail( "memory object", reinterpret_cast<size_t>( alerter ) ) + .scope( typeid(Process) ); + } + + // observer + ODEMX_OBS( ProcessObserver, Alert( this, alerter ) ); + + isAlerted_ = true; + alerter_ = alerter; + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // scheduling + setExecutionTime( getTime() ); + getSimulation().getScheduler().insertSched( this ); +} + +bool Process::isAlerted() const +{ + return isAlerted_; +} + +synchronization::IMemory* Process::getAlerter() const +{ + return alerter_; +} + +void Process::resetAlert() +{ + isAlerted_ = false; + alerter_ = 0; +} + +void Process::resetInterrupt() +{ + isInterrupted_ = false; + interrupter_ = 0; +} + +bool Process::isInterrupted() const +{ + return isInterrupted_; +} + +Sched* Process::getInterrupter() +{ + return interrupter_; +} + +void Process::interrupt() +{ + // ignore self interrupt + if( this == getCurrentSched() ) + { + return; + } + + if( isInterrupted() ) + { + warning << log( "Process::interrupt(): process is already interrupted" ) + .scope( typeid(Process) ); + + // return; ??? + } + + ODEMX_TRACE << log( "interrupted by" ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Interrupt(this)); + + // Set interrupt data + isInterrupted_ = true; + interrupter_ = getCurrentSched(); + + // state management + if( ! setProcessState( RUNNABLE ) ) + { + return; + } + + // scheduling + setExecutionTime( getTime() ); + getSimulation().getScheduler().insertSched( this ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::sleep() +{ + ODEMX_TRACE << log( "sleep" ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Sleep(this)); + + // reset interrupt state + resetInterrupt(); + + // state management + if( ! setProcessState( IDLE ) ) + { + return; + } + + // scheduling + getSimulation().getScheduler().removeSched( this ); + + // continue simulation + getSimulation().switchTo(); +} + +void Process::cancel() +{ + ODEMX_TRACE << log( "cancel" ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Cancel(this)); + + if( setProcessState( TERMINATED ) ) + { + // de-scheduling + if( isScheduled() ) + { + getSimulation().getScheduler().removeSched( this ); + } + + // continue simulation + getSimulation().switchTo(); + } +} + +Sched* Process::getCurrentSched() +{ + return getSimulation().getCurrentSched(); +} + +Process* Process::getCurrentProcess() +{ + return getSimulation().getCurrentProcess(); +} + +SimTime Process::getCurrentTime() const +{ + warning << log( "Process::getCurrentTime(): This method is deprecated. Use Sched::getTime() instead" ).scope( typeid(Process) ); + return getTime (); +} + + +void Process::execute() +{ + if( processState_ != RUNNABLE && processState_ != CURRENT ) + { + fatal << log( "Process::execute(): process is not RUNNABLE or CURRENT" ) + .scope( typeid(Process) ); + + throw SchedulingException( "Process::execute(): process state not CURRENT or RUNNABLE" ); + } + + ODEMX_TRACE << log( "execute process" ) + .detail( "partner", getPartner() ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Execute(this)); + + // old currentSched value is needed in getPartner() + setProcessState( CURRENT ); + + // switch to Coroutine + switchTo(); +} + +Process::ProcessState Process::getProcessState() const +{ + return processState_; +} + +bool Process::setProcessState( ProcessState newState ) +{ + if( processState_ == TERMINATED ) + { + error << log( "Process::setProcessState(): attempt to change state of terminated process" ) + .detail( "partner", getPartner() ).scope( typeid(Process) ); + + return false; + } + + if( newState == CREATED ) + { + error << log( "Process::setProcessState(): process state is already set as CREATED" ) + .detail( "partner", getPartner() ).scope( typeid(Process) ); + + return false; + } + + ProcessState oldState = processState_; + + switch( newState ) + { + case CREATED: + getSimulation().setProcessAsCreated( this ); + break; + case RUNNABLE: + getSimulation().setProcessAsRunnable( this ); + break; + case CURRENT: + getSimulation().setCurrentProcess( this ); + break; + case IDLE: + getSimulation().setProcessAsIdle( this ); + break; + case TERMINATED: + getSimulation().setProcessAsTerminated( this ); + break; + } + + // must set state here because the old state is still needed + // above by getSimulation().setProcessAsXXX + processState_ = newState; + + ODEMX_TRACE << log( "change process state" ) + .valueChange( stateToString( oldState ), stateToString( newState ) ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS_ATTR(ProcessObserver, ProcessState, oldState, newState); + + return true; +} + +void Process::run() +{ + returnValue_ = main(); + + // Process lifeline is finished [returned from main()] + + getSimulation().getScheduler().removeSched( this ); + + // The return value is valid now + validReturn_ = true; + + ODEMX_TRACE << log( "return" ).detail( "value", returnValue_ ).scope( typeid(Process) ); + + // observer + ODEMX_OBS(ProcessObserver, Return(this)); + + setProcessState( TERMINATED ); + + // in case the context is switched, this coroutine will not be reactivated + // so it must be cleared here + Coroutine::clear(); + + // continue simulation + getSimulation().switchTo(); +} + +bool Process::hasReturned() const +{ + return validReturn_; +} + +int Process::getReturnValue() const +{ + if( ! validReturn_ ) + { + warning << log( "Process::getReturnValue(): return value is not valid" ) + .scope( typeid(Process) ); + } + return returnValue_; +} + +Priority Process::getPriority() const +{ + return priority_; +} + +Priority Process::setPriority( Priority newPriority ) +{ + Priority oldPriority = priority_; + priority_ = newPriority; + + ODEMX_TRACE << log( "change priority" ).valueChange( oldPriority, newPriority ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS_ATTR(ProcessObserver, Priority, oldPriority, newPriority); + + // changes in priority may influence ExecutionList + if( isScheduled() || getProcessState() == CURRENT ) + { + getSimulation().getScheduler().inSort( this ); + } + + // precise check for context change because running insertSchedAfter() + // creates unexpected stepping if its call to setPriority() causes + // compSimulation() to be called without need +// if( getCurrentSched() +// && getSimulation().getScheduler().getNextSched() != getCurrentSched() ) +// { + getSimulation().switchTo(); +// } + + return oldPriority; +} + +SimTime Process::getExecutionTime() const +{ + if( processState_ != RUNNABLE && processState_ != CURRENT ) + { + return static_cast< SimTime >(0); + } + return executionTime_; +} + +SimTime Process::setExecutionTime( SimTime newTime ) +{ + if ( newTime < getTime() ) { + error << log( "Process::setExecutionTime(): newTime is less than current time. Setting to current time." ) + .scope( typeid(Process) ); + newTime = getTime(); + } + + SimTime oldTime = executionTime_; + executionTime_ = newTime; + + ODEMX_TRACE << log( "change execution time" ).valueChange( oldTime, newTime ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS_ATTR(ProcessObserver, ExecutionTime, oldTime, newTime); + + return oldTime; +} + +void Process::enqueue( synchronization::ProcessQueue* inQueue ) +{ + assert( inQueue ); + + if( queue_ != 0 ) + { + fatal << log( "Process::enqueue(): process already listed in a queue" ) + .scope( typeid(Process) ); + + throw QueueingException( "Process::enqueue(): process already listed in a queue" ); + } + + queue_ = inQueue; + enqueueTime_ = getTime(); +} + +SimTime Process::getEnqueueTime() const +{ + return enqueueTime_; +} + +void Process::dequeue( synchronization::ProcessQueue* outQueue ) +{ + assert( outQueue ); + + if( queue_ != outQueue ) + { + fatal << log( "Process::dequeue(): process dequeued by wrong queue" ) + .scope( typeid(Process) ); + + throw QueueingException( "Process::dequeue(): process dequeued by wrong queue" ); + } + + queue_ = 0; + dequeueTime_ = getTime(); +} + +SimTime Process::getDequeueTime() const +{ + return dequeueTime_; +} + +synchronization::ProcessQueue* Process::getQueue() const +{ + return queue_; +} + +Priority Process::getQueuePriority() const +{ + return queuePriority_; +} + +Priority Process::setQueuePriority( Priority newQPriority, bool reactivate ) +{ + Priority oldQPriority = queuePriority_; + queuePriority_ = newQPriority; + + ODEMX_TRACE << log( "change queue priority" ).valueChange( oldQPriority, newQPriority ) + .scope( typeid(Process) ); + + // observer + ODEMX_OBS_ATTR(ProcessObserver, QueuePriority, oldQPriority, newQPriority); + + // check if this Process is in a queue, sort queue again + if( queue_ != 0 ) + { + queue_->inSort( this ); + } + + // this Process might have become the first in a waiting queue, + // it will still be blocked in queue if condition not met + if( reactivate ) + { + activate(); + getSimulation().switchTo(); + } + return oldQPriority; +} + +void Process::traceWait( synchronization::IMemoryVector& memvec ) +{ +#ifdef ODEMX_TRACE_ENABLED + // create a record object + data::SimRecord record = log( "wait" ).scope( typeid(Process) ); + + // add details to record: + synchronization::IMemoryVector::const_iterator iter; + for( iter = memvec.begin(); iter != memvec.end(); ++iter ) + { + data::Producer* labeled = dynamic_cast< data::Producer* >( *iter ); + + // memvec contains IMemory*, check if it is castable to labeled object + if( labeled ) + { + record.detail( "memory object", labeled->getLabel() ); + } + else // not a labeled object + { + record.detail( "memory object", "no label" ); + } + } + + // log record to trace channel + ODEMX_TRACE << record; +#endif +} + +const data::Label& Process::getPartner() +{ + if( getSimulation().getCurrentSched() != 0 ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + + return getSimulation().getLabel(); +} + +std::string Process::stateToString( ProcessState state ) +{ + switch( state ) + { + case CREATED: return "CREATED"; + case RUNNABLE: return "RUNNABLE"; + case CURRENT: return "CURRENT"; + case IDLE: return "IDLE"; + case TERMINATED: return "TERMINATED"; + } + // this will never happen + return "THISCANTHAPPEN"; +} + +} } // namespace odemx::base diff --git a/odemx-lite/src/base/Sched.cpp b/odemx-lite/src/base/Sched.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d888aea275b83e1c8136c71a6f2c87c4f94393d2 --- /dev/null +++ b/odemx-lite/src/base/Sched.cpp @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Sched.cpp + * @author Ronald Kluth + * @date created at 2007/04/04 + * @brief Implementation of odemx::base::Sched + * @sa Sched.h + * @since 2.0 + */ + +#include <odemx/base/Sched.h> +#include <odemx/base/Simulation.h> + +namespace odemx { +namespace base { + +//------------------------------------------------------construction/destruction + +Sched::Sched( Simulation& sim, const data::Label& label, SchedType st ) +: data::Producer( sim, label ) +, schedType_( st ) +, scheduled_( false ) +{ +} + +Sched::~Sched() +{ +} + +//-------------------------------------------------------------------status info + +Sched::SchedType Sched::getSchedType() const +{ + return schedType_; +} + +bool Sched::isScheduled() const +{ + return scheduled_; +} + +SimTime Sched::getTime() const +{ + return getSimulation().getTime(); +} + +} // namespace base + +//--------------------------------------------------------------global operators + +// determine order of processes and events in execution list +// by checking for the earlier (smaller) execution time and +// in case of equality comparing which has higher priority +bool operator<( const base::Sched& first, const base::Sched& second ) +{ + return ( first.getExecutionTime() < second.getExecutionTime() ) ? (true) : + (( first.getExecutionTime() > second.getExecutionTime() ) ? (false) : + (first.getPriority() > second.getPriority())); +} + +} // namespace odemx diff --git a/odemx-lite/src/base/Scheduler.cpp b/odemx-lite/src/base/Scheduler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cb9cd754df57e0ed07087bb14b18d36f01366b3 --- /dev/null +++ b/odemx-lite/src/base/Scheduler.cpp @@ -0,0 +1,175 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Scheduler.cpp + * @author Ronald Kluth + * @date created at 2009/03/12 + * @brief Implementation of odemx::base::Scheduler + * @sa Scheduler.h + * @since 3.0 + */ + +#include <odemx/base/Scheduler.h> +#include <odemx/base/Sched.h> +#include <odemx/base/Simulation.h> +#include <odemx/base/Process.h> +#include <odemx/util/Exceptions.h> + +#include <cassert> + +namespace odemx { +namespace base { + +//------------------------------------------------------construction/destruction + +Scheduler::Scheduler( Simulation& sim, const data::Label& label ) +: data::Producer( sim, label ) +, sim_( sim ) +, executionList_( sim, sim.getLabel() + " execution list" ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Scheduler) ); +} + +Scheduler::~Scheduler() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Scheduler) ); +} + +//---------------------------------------------------------------execution modes + +void Scheduler::run() +{ + ODEMX_TRACE << log( "run" ).scope( typeid(Scheduler) ); + + while( ! executionList_.isEmpty() && ! sim_.isFinished() ) + { + executeNextSched(); + } +} + +void Scheduler::runUntil( SimTime stopTime ) +{ + ODEMX_TRACE << log( "run until" ).detail( "time", stopTime ) + .scope( typeid(Scheduler) ); + + while( ! executionList_.isEmpty() + && executionList_.getNextExecutionTime() <= stopTime + && ! sim_.isFinished() ) + { + executeNextSched(); + } + sim_.setCurrentTime( stopTime ); +} + +void Scheduler::step() +{ + ODEMX_TRACE << log( "step" ).scope( typeid(Scheduler) ); + + if( ! executionList_.isEmpty() && ! sim_.isFinished() ) + { + executeNextSched(); + } +} + +//---------------------------------------------------------------sched execution + +void Scheduler::executeNextSched() +{ + // next sched removes itself from list + Sched* next = executionList_.getNextSched(); + assert( next ); + + if( next->getExecutionTime() < sim_.getTime() ) + { + fatal << log( "Scheduler::executeNextSched(): " + "execution list corrupted; invalid execution time" ) + .scope( typeid(Scheduler) ); + + executionList_.logToChannel( fatal ); + + throw SchedulingException( "Execution list corrupted; " + "next execution time < current time" ); + } + + data::StringLiteral recordText; + if( next->getSchedType() == Sched::PROCESS ) + { + recordText = "execute process"; + } + else if( next->getSchedType() == Sched::EVENT ) + { + recordText = "execute event"; + } + + ODEMX_TRACE << log( recordText ) + .detail( "partner", next->getLabel() ) + .scope( typeid(Scheduler) ); + + sim_.setCurrentTime( next->getExecutionTime() ); + + // objects remove themselves from schedule when calling scheduling methods + next->execute(); + sim_.resetCurrentSched(); + sim_.resetCurrentProcess(); + if( next->getSchedType() == Sched::PROCESS ) { + Process* p = static_cast<Process*>(next); + if (p->getProcessState() == Process::TERMINATED) + p->freeStack(); + } + sim_.checkAutoDelete(); +} + +//------------------------------------------------------execution list interface + +void Scheduler::addSched( Sched* s ) +{ + executionList_.addSched( s ); +} + +void Scheduler::insertSched( Sched* s ) +{ + executionList_.insertSched( s ); +} + +void Scheduler::insertSchedBefore( Sched* s, Sched* partner ) +{ + executionList_.insertSchedBefore( s, partner ); +} + +void Scheduler::insertSchedAfter( Sched* s, Sched* partner ) +{ + executionList_.insertSchedAfter( s, partner ); +} + +void Scheduler::removeSched( Sched* s ) +{ + executionList_.removeSched( s ); +} + +void Scheduler::inSort( Sched* s ) +{ + executionList_.inSort( s ); +} + +const ExecutionList& Scheduler::getExecutionList() const +{ + return executionList_; +} + +} } // namespace odemx::base diff --git a/odemx-lite/src/base/Simulation.cpp b/odemx-lite/src/base/Simulation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03b96f0cacd948a5d0ef69fa2712230d344b5903 --- /dev/null +++ b/odemx-lite/src/base/Simulation.cpp @@ -0,0 +1,413 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Simulation.cpp + * @author Ralf Gerstenberger + * @date created at 2002/02/22 + * @brief Implementation of class odemx::base::Simulation + * @sa Simulation.h + * @since 1.0 + */ + +#include <odemx/base/Event.h> +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> +#include <odemx/util/Exceptions.h> + +#include <iostream> +#include <fstream> + +namespace odemx { +namespace base { + +//------------------------------------------------------construction/destruction +static SimulationId unique_id = 0; +SimulationId create_unique_id() { + return unique_id++; +} + +Simulation::Simulation( const data::Label& label, SimulationObserver* obs ) +: data::LoggingManager() +, data::Producer( *this, label ) +, coroutine::CoroutineContext( obs ) +, data::Observable< SimulationObserver >( obs ) +, description_( "no description" ) +, isInitialized_( false ) +, isStopped_( false ) +, startTime_( 0 ) +, currentTime_( 0 ) +, scheduler_( *this, getLabel() + " scheduler" ) +, currentProcess_( 0 ) +, currentSched_( 0 ) +, createdProcesses_() +, runnableProcesses_() +, idleProcesses_() +, terminatedProcesses_() +, autoDelete_( false ) +, uniqueId_( create_unique_id() ) +{ + // since sim owns the channels, there are no consumers for trace records yet + // ODEMX_TRACE << log( "create" ).scope( typeid(Simulation) ); + + ODEMX_OBS(SimulationObserver, Create(this)); +} + +Simulation::Simulation( const data::Label& label, SimTime startTime, SimulationObserver* obs ) +: data::LoggingManager() +, data::Producer( *this, label ) +, coroutine::CoroutineContext( obs ) +, data::Observable< SimulationObserver >( obs ) +, description_( "no description" ) +, isInitialized_( false ) +, isStopped_( false ) +, startTime_( startTime ) +, currentTime_( startTime ) +, scheduler_( *this, getLabel() + " scheduler" ) +, currentProcess_( 0 ) +, currentSched_( 0 ) +, createdProcesses_() +, runnableProcesses_() +, idleProcesses_() +, terminatedProcesses_() +, autoDelete_( false ) +, uniqueId_( create_unique_id() ) +{ + ODEMX_TRACE << log( "create with start time" ).detail( "time", startTime_ ) + .scope( typeid(Simulation) ); + + ODEMX_OBS(SimulationObserver, Create(this)); +} + +Simulation::~Simulation() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Simulation) ); +} + +//----------------------------------------------------------------description/ID + +SimulationId Simulation::getId() const +{ + return uniqueId_; +} + +void Simulation::setDescription( const std::string& description ) +{ + description_ = description; +} + +const std::string& Simulation::getDescription() const +{ + return description_; +} + +//----------------------------------------------------------------initialization + +void Simulation::init() +{ + if( !isInitialized_ ) + { + ODEMX_TRACE << log( "init" ).scope( typeid(Simulation) ); + + // observer + ODEMX_OBS(SimulationObserver, Initialization(this)); + + initSimulation(); + isInitialized_ = true; + } +} + +//----------------------------------------------------------------simulation run + +void Simulation::run() +{ + ODEMX_TRACE << log( "run" ).scope( typeid(Simulation) ); + + // observer + ODEMX_OBS(SimulationObserver, Run(this)); + + init(); + scheduler_.run(); +} + +void Simulation::step() +{ + ODEMX_TRACE << log( "step" ).scope( typeid(Simulation) ); + + // observer + ODEMX_OBS(SimulationObserver, Step(this)); + + init(); + scheduler_.step(); +} + +void Simulation::runUntil( SimTime stopTime ) +{ + assert( stopTime >= currentTime_ ); + + ODEMX_TRACE << log( "run until" ) + .detail( "stop time", stopTime ) + .scope( typeid(Simulation) ); + + // observer + ODEMX_OBS(SimulationObserver, RunUntil(this, stopTime)); + + init(); + scheduler_.runUntil( stopTime ); +} + +//----------------------------------------------------------------simulation end + +void Simulation::exitSimulation() +{ + ODEMX_TRACE << log( "exit" ).scope( typeid(Simulation) ); + + // observer + ODEMX_OBS(SimulationObserver, ExitSimulation(this)); + + // setting isInitialized may not be formally correct, but it will + // effect that isFinished() returns true, which makes sense + // after calling exit on a simulation + isInitialized_ = true; + isStopped_ = true; + + // if this function is called from an active coroutine, + // we need to restore the environment + switchTo(); +} + +bool Simulation::isFinished() const +{ + return isInitialized_ + && ( isStopped_ || scheduler_.getExecutionList().isEmpty() ); +} + +//---------------------------------------------------------------simulation time + +SimTime Simulation::getStartTime() const +{ + return startTime_; +} + +void Simulation::setCurrentTime( SimTime newTime ) +{ + ODEMX_TRACE << log( "time" ) + .valueChange( currentTime_, newTime ) + .scope( typeid(Simulation) ); + + // observer + ODEMX_OBS_ATTR( SimulationObserver, Time, currentTime_, newTime ); + + currentTime_ = newTime; +} + +SimTime Simulation::getTime() const +{ + return currentTime_; +} + +//--------------------------------------------------------------------scheduling + +void Simulation::setCurrentSched( Sched* s ) +{ + assert( s ); + + ODEMX_TRACE << log( "set current" ) + .detail( "partner", s->getLabel() ) + .scope( typeid(Simulation) ); + + // observer + ODEMX_OBS_ATTR(SimulationObserver, CurrentSched, currentSched_, s); + + currentSched_ = s; +} + +void Simulation::setCurrentProcess( Process* p ) +{ + assert( p ); + + // erase process from previous state list + removeProcessFromList( p ); + + currentProcess_ = p; + currentSched_ = p; +} + +Scheduler& Simulation::getScheduler() +{ + return scheduler_; +} + +Sched* Simulation::getCurrentSched() +{ + return currentSched_; +} + +Process* Simulation::getCurrentProcess() +{ + return currentProcess_; +} + +void Simulation::resetCurrentSched() +{ + currentSched_ = 0; +} + +void Simulation::resetCurrentProcess() +{ + currentProcess_ = 0; +} + +//------------------------------------------------------------process management + +ProcessList& Simulation::getCreatedProcesses() +{ + return createdProcesses_; +} + +const ProcessList& Simulation::getCreatedProcesses() const +{ + return createdProcesses_; +} + +ProcessList& Simulation::getRunnableProcesses() +{ + return runnableProcesses_; +} + +const ProcessList& Simulation::getRunnableProcesses() const +{ + return runnableProcesses_; +} + +ProcessList& Simulation::getIdleProcesses() +{ + return idleProcesses_; +} + +const ProcessList& Simulation::getIdleProcesses() const +{ + return idleProcesses_; +} + +ProcessList& Simulation::getTerminatedProcesses() +{ + return terminatedProcesses_; +} + +const ProcessList& Simulation::getTerminatedProcesses() const +{ + return terminatedProcesses_; +} + +void Simulation::setProcessAsCreated( Process* p ) +{ + assert( p ); + + ODEMX_OBS(SimulationObserver, ChangeProcessList(this, p, CREATED)); + + // insert p + p->simListIter_ = createdProcesses_.insert( createdProcesses_.end(), p ); +} + +void Simulation::setProcessAsRunnable( Process* p ) +{ + assert( p ); + + // erase process from previous state list + removeProcessFromList( p ); + + ODEMX_OBS(SimulationObserver, ChangeProcessList(this, p, RUNNABLE)); + + // insert p + p->simListIter_ = runnableProcesses_.insert( runnableProcesses_.end(), p ); +} + +void Simulation::setProcessAsIdle( Process* p ) +{ + assert( p ); + + // erase process from previous state list + removeProcessFromList( p ); + + ODEMX_OBS(SimulationObserver, ChangeProcessList(this, p, IDLE)); + + // insert p + p->simListIter_ = idleProcesses_.insert( idleProcesses_.end(), p ); +} + +void Simulation::setProcessAsTerminated( Process* p ) +{ + assert( p ); + + // erase process from previous state list + removeProcessFromList( p ); + + ODEMX_OBS(SimulationObserver, ChangeProcessList(this, p, TERMINATED)); + + // insert p + p->simListIter_ = terminatedProcesses_.insert( terminatedProcesses_.end(), p ); +} + +void Simulation::removeProcessFromList( Process* p ) +{ + assert( p ); + + switch ( p->getProcessState() ) + { + case Process::CREATED: + createdProcesses_.erase( p->simListIter_ ); + break; + case Process::RUNNABLE: + runnableProcesses_.erase( p->simListIter_ ); + break; + case Process::IDLE: + idleProcesses_.erase( p->simListIter_ ); + break; + case Process::TERMINATED: + // usually should not happen, no reactivation after termination + // however, this function may be used to remove processes from lists + // before their destruction, so no warning or error + terminatedProcesses_.erase( p->simListIter_ ); + break; + default: // Process::CURRENT, no list needed + break; + } +} + +//---------------------------------------------automatic process object deletion + +void Simulation::autoDeleteProcesses( bool value ) +{ + autoDelete_ = value; +} + +void Simulation::checkAutoDelete() +{ + if( autoDelete_ ) + { + ProcessList::iterator iter = terminatedProcesses_.begin(); + while( iter != terminatedProcesses_.end() ) + { + delete *iter++; + } + terminatedProcesses_.clear(); + } +} + +} } // namespace odemx::base diff --git a/odemx-lite/src/base/cellular_automaton/Cell.cpp b/odemx-lite/src/base/cellular_automaton/Cell.cpp new file mode 100644 index 0000000000000000000000000000000000000000..554515c09e71fdad133f54bce7801152591dc6f1 --- /dev/null +++ b/odemx-lite/src/base/cellular_automaton/Cell.cpp @@ -0,0 +1,515 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Cell.cpp + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Implementation of class Cell + + \sa Cell.h + + \since 3.0 + */ +#include <exception> +#include <iostream> +#include <odemx/base/cellular_automaton/Cell.h> +#include <odemx/base/cellular_automaton/CellMonitor.h> +#include <odemx/base/cellular_automaton/Transition.h> +#include <odemx/base/cellular_automaton/CellVariablesContainer.h> + +using namespace odemx::base; +using namespace odemx::base::cellular; +using namespace std; + +//------------------------------------------------------------------------------construction/destruction +Cell::Cell(unsigned row, unsigned column, unsigned level, unsigned dimension, unsigned inputDimension, unsigned outputDimension, CellMonitor* monitor) +: monitor(monitor) +, stateDimension(dimension) +, inputDimension(inputDimension) +, outputDimension(outputDimension) +, isBoundary(false) +, pushed(false) +{ + cellPosition = new CellPosition(row, column, level, monitor->getRowCount(), monitor->getColumnCount(), monitor->getLevelCount()); + + typeOfNeighborhood.neighborhoodType = MOORE; + typeOfNeighborhood.radius = 1; +} + +Cell::~Cell() { + +} + +void Cell::calculateNeighborhood() { + + switch (typeOfNeighborhood.neighborhoodType) { + case MOORE: + calculateMooreNeighborhood(typeOfNeighborhood.radius); + break; + case NEUMANN: + calculateVonNeumannNeighborhood(typeOfNeighborhood.radius); + break; + case MOORETORUS: + calculateMoore2DTorusNeighborhood(typeOfNeighborhood.radius); + break; + case NEUMANNTORUS: + calculateNeumann2DTorusNeighborhood(typeOfNeighborhood.radius); + break; + case MOOREXTUBE: + calculateMoore2DXAxisTubeNeighborhood(typeOfNeighborhood.radius); + break; + case NEUMANNXTUBE: + calculateNeumann2DXAxisTubeNeighborhood(typeOfNeighborhood.radius); + break; + case MOOREYTUBE: + calculateMoore2DYAxisTubeNeighborhood(typeOfNeighborhood.radius); + break; + case NEUMANNYTUBE: + calculateNeumann2DYAxisTubeNeighborhood(typeOfNeighborhood.radius); + break; + default: + calculateMooreNeighborhood(typeOfNeighborhood.radius); + break; + } +} + +void Cell::pushValue() { + this->pushed = true; +} + +std::vector<double> Cell::pullValue(unsigned variableIndex) { + + std::vector<double> neigborhoodCellsValuesVector; + try{ + for (std::map<CellPosition, Cell*, ComparePositions>::iterator iter = neighborhoodCellsMap.begin(); iter != neighborhoodCellsMap.end(); ++iter) { + checkIndexBoundary(variableIndex, (iter->second->getDimension() - 1), "Cell::pullValue(unsigned variableIndex)"); + neigborhoodCellsValuesVector.push_back(monitor->cellVariablesContainer->getOutputValue(iter->second->getOutputBaseIndex(), variableIndex)); + } + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } + + return neigborhoodCellsValuesVector; + +} + +void Cell::setValue(unsigned variableIndex, double value) { + try { + checkIndexBoundary(variableIndex, (this->stateDimension - 1), "Cell::setValue(unsigned variableIndex, double value)"); + this->monitor->cellVariablesContainer->setStateValue(this->stateBaseIndex, variableIndex, value); + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } +} + +double Cell::getValue(unsigned variableIndex) { + try { + checkIndexBoundary(variableIndex, (this->stateDimension - 1), "Cell::getValue(unsigned variableIndex)"); + return this->monitor->cellVariablesContainer->getStateValue(this->stateBaseIndex, variableIndex); + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } +} + +void Cell::setOutputValue(unsigned variableIndex, double value) { + try { + checkIndexBoundary(variableIndex, (this->outputDimension -1), "Cell::setOutputValue(unsigned variableIndex, double value)"); + this->monitor->cellVariablesContainer->setOutputValue(this->outputBaseIndex, variableIndex, value); + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } +} + +double Cell::getOutputValue(unsigned variableIndex) { + try { + checkIndexBoundary(variableIndex, (this->outputDimension - 1), "Cell::getOutputValue(unsigned variableIndex)"); + return this->monitor->cellVariablesContainer->getOutputValue(this->outputBaseIndex, variableIndex); + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } +} + +void Cell::setInputValue(unsigned variableIndex, double value) { + try { + checkIndexBoundary(variableIndex, (this->inputDimension - 1), "Cell::setInputValue(unsigned variableIndex, double value)"); + this->monitor->cellVariablesContainer->setInputValue(this->inputBaseIndex, variableIndex, value); + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } +} + +double Cell::getInputValue(unsigned variableIndex) { + try { + checkIndexBoundary(variableIndex, (this->inputDimension - 1), "Cell::getInputValue(unsigned variableIndex)"); + return this->monitor->cellVariablesContainer->getInputValue(this->inputBaseIndex, variableIndex); + } catch(out_of_range e) { + std::cerr << e.what() << std::endl; + } +} + +void Cell::setTransition(Transition* transition) { + if(transition) { + transition->setCell(this); + this->transitions.push_back(transition); + } + else { + throw new NotAssignedException("Transition", "Cell"); + } +} + +void Cell::deleteTransition(Transition* transition) { + + if(transition) { + list<Transition*>::iterator iter = find(this->transitions.begin(), + this->transitions.end(), transition); + //..and delete + if (*iter == transition) { + this->transitions.erase(iter); + } + transition->cell = 0; + } + else { + throw new NotAssignedException("Transition", "Cell"); + } +} + +unsigned Cell::getDimension() { + return this->stateDimension; +} + +unsigned Cell::getInputDimension() { + return this->inputDimension; +} + +unsigned Cell::getOutputDimension() { + return this->outputDimension; +} + +void Cell::setIsBoundary() { + this->isBoundary = true; + this->monitor->calculateNeighboorhood(); +} + +bool Cell::isPartOfBoundary() { + return this->isBoundary; +} + +void Cell::setPosition(unsigned row, unsigned column, unsigned level) { + cellPosition->setPosition(row, column, level); +} + +CellPosition* Cell::getPosition() { + return this->cellPosition; +} + +void Cell::setNeighborhoodSettings(unsigned neighborhoodType, unsigned radius, bool calcNeighborhood) { + this->typeOfNeighborhood.neighborhoodType = neighborhoodType; + this->typeOfNeighborhood.radius = radius; + if(calcNeighborhood) calculateNeighborhood(); +} + +std::map<CellPosition, Cell*, ComparePositions> Cell::getNeighbors() { + return neighborhoodCellsMap; +} + +Cell* Cell::searchNeighbor(unsigned row, unsigned column, unsigned level) { + CellPosition tempPosition(row, column, level, cellPosition->cellRows, cellPosition->cellColumns, cellPosition->cellLevel); + map<CellPosition, Cell*, ComparePositions>::iterator iter = neighborhoodCellsMap.find(tempPosition); + + if(iter != neighborhoodCellsMap.end()) { + return iter->second; + } + else { + return 0; + } +} + +void Cell::calculateMooreNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + unsigned levelCount = monitor->getLevelCount(); + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + unsigned levelNumberIndex = cellPosition->level; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, levelCount); + + for (int i = 0; i < rowCount; ++i) { + for (int j = 0; j < columnCount; ++j) { + for (int k = 0; k < levelCount; ++k) { + if((std::abs(i-(int)rowNumberIndex) <= radius && std::abs(j-(int)columnNumberIndex) <= radius && (std::abs(k-(int)levelNumberIndex) <= radius)) && !monitor->getCell(i,j,k)->isPartOfBoundary()) { + if(!(i == rowNumberIndex && j == columnNumberIndex && k == levelNumberIndex)) { + neighborCellPosition.setPosition(i,j,k); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(rowCount*(k*columnCount + j) + i); + } + } + } + } + } +} + +void Cell::calculateVonNeumannNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + unsigned levelCount = monitor->getLevelCount(); + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + unsigned levelNumberIndex = cellPosition->level; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, levelCount); + + for (int i = 0; i < rowCount; ++i) { + for (int j = 0; j < columnCount; ++j) { + for (int k = 0; k < levelCount; ++k) { + if((std::abs(i-(int)rowNumberIndex) + std::abs(j-(int)columnNumberIndex) + std::abs(k-(int)levelNumberIndex) <= radius) && !monitor->getCell(i,j,k)->isPartOfBoundary()) { + if(!(i == rowNumberIndex && j == columnNumberIndex && k == levelNumberIndex)) + neighborCellPosition.setPosition(i,j,k); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(rowCount*(k*columnCount + j) + i); + } + } + } + } +} + +void Cell::calculateMoore2DTorusNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + + unsigned actualI = 0, actualJ = 0; + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, 0); + + for (int i = -1*(int)radius; i < rowCount + radius; ++i) { + for (int j = -1*(int)radius; j < columnCount + radius; ++j) { + if((std::abs(i-(int)rowNumberIndex) <= radius) && (std::abs(j-(int)columnNumberIndex) <= radius) ) {//&& !monitor->getCell(i,j,0)->isPartOfBoundary()) { + if(!(rowNumberIndex == i % rowCount && columnNumberIndex == j % columnCount)) { + if(i < 0) actualI = (i + rowCount); + else if(i > rowCount) actualI = i % rowCount; + else actualI= i; + if(j < 0) actualJ = (j + rowCount); + else if(j > columnCount) actualJ = j % columnCount; + else actualJ = j; + neighborCellPosition.setPosition(actualI,actualJ,0); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(actualI*columnCount + actualJ); + } + } + } + } +} + +void Cell::calculateMoore2DXAxisTubeNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + + unsigned actualJ = 0; + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, 0); + for (int i = 0; i < rowCount; ++i) { + for (int j = -1*(int)radius; j < (int)columnCount + (int)radius; ++j) { + if((std::abs(i-(int)rowNumberIndex) <= radius) && (std::abs(j-(int)columnNumberIndex) <= radius) ) {//&& !monitor->getCell(i,j,0)->isPartOfBoundary()) { + if(!(rowNumberIndex == i && columnNumberIndex == j % (int)columnCount)) { + if(j < 0) actualJ = (j + columnCount); + else if(j >= columnCount) actualJ = j % columnCount; + else actualJ = j; + neighborCellPosition.setPosition(i,actualJ,0); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(i*columnCount + actualJ); + } + } + } + } +} + +void Cell::calculateMoore2DYAxisTubeNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + + unsigned actualI = 0; + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, 0); + + for (int i = -1*(int)radius; i < (int)rowCount + (int)radius; ++i) { + for (int j = 0; j < columnCount; ++j) { + if((std::abs(i-(int)rowNumberIndex) <= radius) && (std::abs(j-(int)columnNumberIndex) <= radius) ) {//&& !monitor->getCell(i,j,0)->isPartOfBoundary()) { + if(!(rowNumberIndex == i % (int)rowCount && columnNumberIndex == j)) { + if(i < 0) actualI = (i + rowCount); + else if(i >= rowCount) actualI = i % rowCount; + else actualI= i; + neighborCellPosition.setPosition(actualI,j,0); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(actualI*columnCount + j); + } + } + } + } +} + + +void Cell::calculateNeumann2DTorusNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + + unsigned actualI = 0, actualJ = 0; + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, 0); + + for (int i = -1*(int)radius; i < rowCount + radius; ++i) { + for (int j = -1*(int)radius; j < columnCount + radius; ++j) { + if((std::abs(i-(int)rowNumberIndex) + std::abs(j-(int)columnNumberIndex) <= radius) ) {//&& !monitor->getCell(i,j,0)->isPartOfBoundary()) { + if(!(rowNumberIndex == i % rowCount && columnNumberIndex == j % columnCount)) { + if(i < 0) actualI = (i + rowCount); + else if(i > rowCount) actualI = i % rowCount; + else actualI= i; + if(j < 0) actualJ = (j + rowCount); + else if(j > columnCount) actualJ = j % columnCount; + else actualJ = j; + neighborCellPosition.setPosition(actualI,actualJ,0); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(actualI*columnCount + actualJ); + } + } + } + } +} + +void Cell::calculateNeumann2DXAxisTubeNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + + unsigned actualJ = 0; + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, 0); + + for (int i = 0; i < rowCount; ++i) { + for (int j = -1*(int)radius; j < (int)columnCount + (int)radius; ++j) { + if((std::abs(i-(int)rowNumberIndex) + std::abs(j-(int)columnNumberIndex) <= radius) ) {//&& !monitor->getCell(i,j,0)->isPartOfBoundary()) { + if(!(rowNumberIndex == i && columnNumberIndex == j % (int)columnCount)) { + if(j < 0) actualJ = (j + columnCount); + else if(j >= columnCount) actualJ = j % columnCount; + else actualJ = j; + neighborCellPosition.setPosition(i,actualJ,0); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(i*columnCount + actualJ); + } + } + } + } +} + +void Cell::calculateNeumann2DYAxisTubeNeighborhood(unsigned radius) { + + unsigned rowCount = monitor->getRowCount(); + unsigned columnCount = monitor->getColumnCount(); + + unsigned actualI = 0; + + unsigned rowNumberIndex = cellPosition->row; + unsigned columnNumberIndex = cellPosition->column; + + CellPosition neighborCellPosition(0, 0, 0, rowCount, columnCount, 0); + + for (int i = -1*(int)radius; i < (int)rowCount + (int)radius; ++i) { + for (int j = 0; j < columnCount; ++j) { + if((std::abs(i-(int)rowNumberIndex) + std::abs(j-(int)columnNumberIndex) <= radius) ) {//&& !monitor->getCell(i,j,0)->isPartOfBoundary()) { + if(!(rowNumberIndex == i % (int)rowCount && columnNumberIndex == j)) { + if(i < 0) actualI = (i + columnCount); + else if(i >= rowCount) actualI = i % rowCount; + else actualI= i; + neighborCellPosition.setPosition(actualI,j,0); + neighborhoodCellsMap[neighborCellPosition] = monitor->getCell_(actualI*columnCount + j); + } + } + } + } +} + +void Cell::calculateAlternativeNeighborhood(unsigned radius) { + int i = 0; + for(list<Transition*>::iterator iter = this->transitions.begin(); iter != this->transitions.end(); ++iter) { + neighborhoodCellsMap = (*iter)->calculateAlternativeNeighborhood(radius); + i++; + } + if(i == 0) + throw new NotAssignedException("Cell", "Transition"); +} + +void Cell::checkIndexBoundary(unsigned index, unsigned indexBoundary, std::string what) { + if(index > indexBoundary) { + throw std::out_of_range("The index in " + what + " is out of bounds."); + } +} + +void Cell::setBaseIndex(unsigned baseIndex) { + this->stateBaseIndex = baseIndex; +} + +void Cell::setInputBaseIndex(unsigned baseIndex) { + this->inputBaseIndex = baseIndex; +} + +void Cell::setOutputBaseIndex(unsigned baseIndex) { + this->outputBaseIndex = baseIndex; +} + +unsigned Cell::getBaseIndex() { + return this->stateBaseIndex; +} + +unsigned Cell::getInputBaseIndex() { + return this->inputBaseIndex; +} + +unsigned Cell::getOutputBaseIndex() { + return this->outputBaseIndex; +} + +void Cell::setMonitor(CellMonitor* monitor) { + if(monitor) { + this->monitor = monitor; + } + else { + throw new NotAssignedException("Monitor", "Cell"); + } +} + +CellMonitor* Cell::getMonitor() { + return this->monitor; +} diff --git a/odemx-lite/src/base/cellular_automaton/CellMonitor.cpp b/odemx-lite/src/base/cellular_automaton/CellMonitor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c540c6c21ea42c2ae924fe83568c01f7604ffe3 --- /dev/null +++ b/odemx-lite/src/base/cellular_automaton/CellMonitor.cpp @@ -0,0 +1,647 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file CellMonitor.cpp + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Implementation of class CellMonitor + + \sa CellMonitor.h + + \since 3.0 +*/ +#include <iomanip> +#include <iostream> +#include <fstream> +#include <odemx/base/cellular_automaton/CellMonitor.h> +#include <odemx/base/cellular_automaton/CellVariablesContainer.h> +#include <odemx/base/cellular_automaton/Cell.h> +#include <odemx/base/Scheduler.h> +#include <odemx/base/Simulation.h> + +using namespace odemx::base; +using namespace odemx::base::cellular; +using namespace std; + +//----------------------------------------------------------------------------------construction/destruction +CellMonitor::CellMonitor(Simulation& sim, const data::Label& l, unsigned variablesInCount, unsigned variablesOutCount, unsigned cellRows, unsigned cellColumns, unsigned cellLevel, double timestep, unsigned cellDimension, ProcessObserver* o) +: Process(sim, l, o) +, cellDimension(cellDimension) +, variablesInCount(variablesInCount) +, variablesOutCount(variablesOutCount) +, cellRows(cellRows) +, cellColumns(cellColumns) +, cellLevel(cellLevel) +, timestep(timestep) +, timeLimit(0) +{ + typeOfNeighborhood.neighborhoodType = MOORE; + typeOfNeighborhood.radius = 1; + cellVariablesContainer = new CellVariablesContainer(cellRows, cellColumns, cellLevel, variablesInCount, variablesOutCount, cellDimension); + generateCellularAutomaton(cellRows, cellColumns, cellLevel, cellDimension); + calculateNeighboorhood(); + + ODEMX_TRACE << log( "create" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, Create(this)); +} + +CellMonitor::CellMonitor(Simulation& sim, const data::Label& l, const char*const configFileName, ProcessObserver* o) +: Process(sim, l, o) +, timeLimit(0) +{ + setParameterFromConfigFile(configFileName); + cellVariablesContainer = new CellVariablesContainer(cellRows, cellColumns, cellLevel, variablesInCount, variablesOutCount, cellDimension); + generateCellularAutomaton(cellRows, cellColumns, cellLevel, cellDimension); + calculateNeighboorhood(); + + ODEMX_TRACE << log( "create with configuration file" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, Create(this)); +} + +CellMonitor::CellMonitor(Simulation& sim, const data::Label& l, const char*const configFileName, const char*const startDataFileName, ProcessObserver* o) +: Process(sim, l, o) +, timeLimit(0) +{ + setParameterFromConfigFile(configFileName); + cellVariablesContainer = new CellVariablesContainer(cellRows, cellColumns, cellLevel, variablesInCount, variablesOutCount, cellDimension); + generateCellularAutomaton(cellRows, cellColumns, cellLevel, cellDimension); + setStartDataFromConfigFile(startDataFileName); + calculateNeighboorhood(); + + ODEMX_TRACE << log( "create with configuration file and start data file" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, Create(this)); +} + +CellMonitor::~CellMonitor(){ + if (cellVariablesContainer) { + delete cellVariablesContainer; + } +} + +int CellMonitor::main() { + + //initialize arrays + for(int i = 0; i < cellVector.size(); ++i){ + if(cellVector[i]->isPartOfBoundary()) continue; + for(std::list<Transition*>::iterator iter = cellVector[i]->transitions.begin(); iter != cellVector[i]->transitions.end(); ++iter) { + (*iter)->outputFunction(); + } + } + + while (getTime() < timeLimit) { + //notifyValidState(); + + ODEMX_TRACE << log( "new valid state" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, NewValidState(this)); + + ODEMX_TRACE << log( "begin calculation of state changes" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, BeginCalcStateChanges(this)); + + for(int i = 0; i < cellVector.size(); ++i) { + if(cellVector[i]->isPartOfBoundary()) continue; + for(std::list<Transition*>::iterator iter = cellVector[i]->transitions.begin(); iter != cellVector[i]->transitions.end(); ++iter) { + (*iter)->transitionFunction(getTime()); + } + } + + for(int i = 0; i < cellVector.size(); ++i){ + if(cellVector[i]->isPartOfBoundary()) continue; + for(std::list<Transition*>::iterator iter = cellVector[i]->transitions.begin(); iter != cellVector[i]->transitions.end(); ++iter) { + (*iter)->outputFunction(); + } + } + + ODEMX_TRACE << log( "end calculation of state changes" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, EndCalcStateChanges(this)); + + holdFor(timestep); + } + return 0; +} + +void CellMonitor::setTimeLimit(SimTime time) { + timeLimit = time; + + ODEMX_TRACE << log( "set time limit" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, SetTimeLimit(this, timeLimit)); + +} + +SimTime CellMonitor::getTimeLimit() { + return timeLimit; +} + +void CellMonitor::setTransitionToCells(Transition* transition) { + + for (int i = 0; i < this->cellVector.size(); ++i) { + cellVector[i]->setTransition(transition); + } + + ODEMX_TRACE << log( "sets transition to all cells" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, SetTransitionToCells(this)); +} + +//----------------------------------------------------------- temp function for printing values +double* CellMonitor::getValues() { + return this->cellVariablesContainer->getOutputValues(); +} + +unsigned CellMonitor::getRowCount() { + return cellRows; +} + +unsigned CellMonitor::getColumnCount() { + return cellColumns; +} + +unsigned CellMonitor::getLevelCount() { + return cellLevel; +} + +void CellMonitor::setIsBoundaryCell(unsigned row, unsigned column, unsigned level) { + this->cellVector[cellRows * (cellColumns * level + column) + row]->isPartOfBoundary(); +} + +void CellMonitor::setCellValue(unsigned row, unsigned column, unsigned level, unsigned variableIndex, double value) { + this->cellVector[cellRows * (cellColumns * level + column) + row]->setValue(variableIndex, value); +} + +double CellMonitor::getCellValue(unsigned row, unsigned column, unsigned level, unsigned variableIndex) { + this->cellVector[cellRows * (cellColumns * level + column) + row]->getValue(variableIndex); +} + +unsigned CellMonitor::getNeighborhoodType() { + return this->typeOfNeighborhood.neighborhoodType; +} + +unsigned CellMonitor::getNeighborhoodRadius() { + return this->typeOfNeighborhood.radius; +} + +Cell* CellMonitor::getCell(unsigned row, unsigned column, unsigned level) { + return this->cellVector[cellRows * (cellColumns * level + column) + row]; +} + +Cell* CellMonitor::getCell_(unsigned cellIndex) { + return this->cellVector[cellIndex]; +} + +void CellMonitor::setNeighborhoodSettings(unsigned neighborhoodType, unsigned radius) { + for (int i = 0; i < this->cellVector.size(); ++i) { + getCell_(i)->setNeighborhoodSettings(neighborhoodType, radius); + } + this->typeOfNeighborhood.neighborhoodType = neighborhoodType; + this->typeOfNeighborhood.radius = radius; + + ODEMX_TRACE << log( "sets neighborhood" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, SetNeighborhoodSettings(this, neighborhoodType, radius)); +} + +void CellMonitor::setStartDataFromConfigFile(std::string fileName) { + + string line; + ifstream is(fileName.c_str()); + + if(!is) { + cout << "Could not open file!" << endl; + exit(1); + } + + unsigned row = 0, column = 0, level = 0, statevariable_index = 0, outputvariable_index = 0, inputvariable_index = 0, radius = 0; + + double statevariable = 0, outputvariable = 0, inputvariable = 0; + + string tempstring = ""; + + Cell* cell; + + string::size_type i; + + while(getline(is, line)) { + + while(line.find_first_not_of ( " \t\n\v" ) == string::npos) { + getline(is, line); + } + + statevariable = -1, outputvariable = -1, inputvariable = -1; + + if(line.find("<cell row-index=\"") != string::npos) { + statevariable_index = 0, outputvariable_index = 0, inputvariable_index = 0; + + line.erase(0, line.find('\"')+1); + tempstring = line.substr(0, line.find("\" column-index=\"")+1); + istringstream row_tmp(tempstring); + row_tmp >> row; + + line.erase(0, line.find('\"')+1); + line.erase(0, line.find('\"')+1); + tempstring = line.substr(0, line.find("\" level-index=\"")+1); + istringstream column_tmp(tempstring); + column_tmp >> column; + + line.erase(0, line.find('\"')+1); + line.erase(0, line.find('\"')+1); + tempstring = line.substr(0, line.find("\">")+1); + istringstream level_tmp(tempstring); + level_tmp >> level; + cell = getCell(row, column, level); + } + + while(line.find("<statevariable>") != string::npos || line.find("</statevariable>") != string::npos) { + if(line.find("</statevariable>") != string::npos) { + statevariable_index++; + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + continue; + } + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream statevariable_tmp(line); + statevariable_tmp >> statevariable; + cell->setValue(statevariable_index, statevariable); + } + + while(line.find("<outputvariable>") != string::npos || line.find("</outputvariable>") != string::npos) { + if(line.find("</outputvariable>") != string::npos) { + outputvariable_index++; + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + continue; + } + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream outputvariable_tmp(line); + outputvariable_tmp >> outputvariable; + cell->setOutputValue(outputvariable_index, outputvariable); + } + + while(line.find("<inputvariable>") != string::npos || line.find("</inputvariable>") != string::npos) { + if(line.find("</inputvariable>") != string::npos) { + inputvariable_index++; + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + continue; + } + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream inputvariable_tmp(line); + inputvariable_tmp >> inputvariable; + cell->setInputValue(inputvariable_index, inputvariable); + } + + if(line.find("<neighborhoodtype>") != string::npos || line.find("</inputvariable>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + transform(line.begin(), line.end(), line.begin(), (int(*)(int))toupper); + if(line.find("MOORE") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 0; + if(line.find("NEUMANN") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 1; + if(line.find("MOORETORUS") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 2; + if(line.find("NEUMANNTORUS") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 3; + if(line.find("MOOREXTUBE") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 4; + if(line.find("NEUMANNXTUBE") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 5; + if(line.find("MOOREYTUBE") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 6; + if(line.find("NEUMANNYTUBE") != string::npos) cell->typeOfNeighborhood.neighborhoodType = 7; + + ODEMX_TRACE << log( "sets neighborhood type for one cell" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, SetNeighborhoodType(this, typeOfNeighborhood.neighborhoodType, cell->getPosition())); + } + + if(line.find("<radius>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> radius; + cell->typeOfNeighborhood.radius = radius; + + ODEMX_TRACE << log( "sets neighborhood radius for one cell" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, SetNeighborhoodRadius(this, typeOfNeighborhood.radius, cell->getPosition())); + } + + if(line.find("<boundary>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + transform(line.begin(), line.end(), line.begin(), (int(*)(int))toupper); + if(line.find("TRUE") != string::npos) cell->setIsBoundary(); + } + } +} + +void CellMonitor::setParameterFromConfigFile(std::string fileName) { + + string line; + ifstream is(fileName.c_str()); + int k = -1; + + bool settedNeighborhoodType = false, settedRadius = false; + + if(!is) { + cout << "Could not open file!" << endl; + exit(1); + } + + while(getline(is, line)) { + if(line.find("<rowcount>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + cellRows = k; + } + if(line.find("<columncount>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + cellColumns = k; + } + if(line.find("<levelcount>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + cellLevel = k; + } + if(line.find("<outputvariablesize>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + variablesOutCount = k; + } + if(line.find("<inputvariablesize>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + variablesInCount = k; + } + if(line.find("<celldimension>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + cellDimension = k; + } + if(line.find("<timestep>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + timestep = k; + } + if(line.find("<neighboorhoodtype>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + transform(line.begin(), line.end(), line.begin(), (int(*)(int))toupper); + if(line.find("MOORE") != string::npos) typeOfNeighborhood.neighborhoodType = 0; + if(line.find("NEUMANN") != string::npos) typeOfNeighborhood.neighborhoodType = 1; + if(line.find("MOORETORUS") != string::npos) typeOfNeighborhood.neighborhoodType = 2; + if(line.find("NEUMANNTORUS") != string::npos) typeOfNeighborhood.neighborhoodType = 3; + if(line.find("MOOREXTUBE") != string::npos) typeOfNeighborhood.neighborhoodType = 4; + if(line.find("NEUMANNXTUBE") != string::npos) typeOfNeighborhood.neighborhoodType = 5; + if(line.find("MOOREYTUBE") != string::npos) typeOfNeighborhood.neighborhoodType = 6; + if(line.find("NEUMANNYTUBE") != string::npos) typeOfNeighborhood.neighborhoodType = 7; + + settedNeighborhoodType = true; + } + if(line.find("<radius>") != string::npos) { + do { + getline(is, line); + } while(line.find_first_not_of ( " \t\n\v" ) == string::npos); + istringstream tmp(line); + tmp >> k; + typeOfNeighborhood.radius = k; + + settedRadius = true; + } + + if(settedNeighborhoodType && settedRadius) { + ODEMX_TRACE << log( "sets neighborhood" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, SetNeighborhoodSettings(this, typeOfNeighborhood.neighborhoodType, typeOfNeighborhood.radius)); + } + } +} + +//-----------------------------------------------------------generate cellular automaton +void CellMonitor::generateCellularAutomaton(unsigned rows, unsigned columns, unsigned level, unsigned cellDimension){ + + Cell* cell; + unsigned variablesStateCounts = 0, variablesInCounts = 0, variablesOutCounts = 0; + //generate cells and set the parameters + for(int k = 0; k < level; ++k){ + for(int j = 0; j < columns; ++j) { + for(int i = 0; i < rows; ++i) { + cell = new Cell(i, j, k, this->variablesInCount, this->variablesOutCount, this->cellDimension, this); + cell->setBaseIndex(variablesStateCounts); + cell->setInputBaseIndex(variablesInCounts); + cell->setOutputBaseIndex(variablesOutCounts); + cell->setNeighborhoodSettings(typeOfNeighborhood.neighborhoodType, typeOfNeighborhood.radius, false); + variablesStateCounts += cell->getDimension(); + variablesInCounts += cell->getInputDimension(); + variablesOutCounts += cell->getOutputDimension(); + this->cellVector.push_back(cell); + } + } + } + + ODEMX_TRACE << log( "generate cellular automaton" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, GenerateCellularAutomaton(this)); +} + +void CellMonitor::calculateNeighboorhood() { + for(int i = 0; i < cellColumns*cellRows*cellLevel; ++i) { + this->cellVector[i]->calculateNeighborhood(); + } + + ODEMX_TRACE << log( "calculate neighborhood" ).scope( typeid(CellMonitor) ); + + // observer + ODEMX_OBS(CellMonitorObserver, CalculateNeighboorhood(this)); +} + +CellMonitorTrace::CellMonitorTrace(CellMonitor* cellMonitor, const string & fileName) +: out(0), + firstTime(true), + fileName(fileName), + cellMonitor(cellMonitor) +{ +#ifdef ODEMX_USE_OBSERVATION + if( cellMonitor != 0 ) + { + cellMonitor->data::Observable< CellMonitorObserver >::addObserver( this ); + } +#endif + + if( ! fileName.empty() ) + { + openFile( fileName ); + } + else if( cellMonitor != 0 ) + { + std::string fn = cellMonitor->getLabel(); + fn += "_trace.xml"; + openFile( fn ); + } +} + +CellMonitorTrace::~CellMonitorTrace() +{ + if( out == 0 || out == &std::cout ) + { + return; + } + *out << "</tracefile>" << endl; + + static_cast< std::ofstream* >( out )->close(); + delete out; +} + +void CellMonitorTrace::onNewValidState( CellMonitor* sender ) +{ + using namespace std; + + assert( sender != 0 ); + + if( firstTime ) + { + if( out == 0 ) + { + std::string fn = fileName; + fn += "_trace.xml"; + openFile( fn ); + } + + *out << "<?xml version=\"1.0\"?>" << endl; + *out << "<!DOCTYPE tracefile [" << endl; + *out << " <!ELEMENT tracefile (ca)+>" << endl; + *out << " <!ELEMENT ca (cell)+>" << endl; + *out << endl; + *out << " <!ELEMENT cell (statevariable+, outputvariable+, inputvariable+)>" << endl; + *out << endl; + *out << " <!ELEMENT statevariable (#PCDATA)>" << endl; + *out << " <!ELEMENT outputvariable (#PCDATA)>" << endl; + *out << " <!ELEMENT inputvariable (#PCDATA)>" << endl; + *out << endl; + *out << " <!ATTLIST tracefile name CDATA #REQUIRED>" << endl; + *out << " <!ATTLIST ca time CDATA #REQUIRED>" << endl; + *out << " <!ATTLIST cell" << endl; + *out << " row-index CDATA #REQUIRED" << endl; + *out << " column-index CDATA #REQUIRED" << endl; + *out << " level-index CDATA #REQUIRED" << endl; + *out << " >" << endl; + *out << "]>" << endl; + + *out << endl; + *out << endl; + *out << "<tracefile name=\"T R A C E F I L E F O R C E L L U L A R A U T O M A T O N " << sender->getLabel() << "\">" << endl; + firstTime=false; + } + + ( *out ).setf( std::ios::showpoint ); + ( *out ).setf( std::ios::fixed ); + + *out << setprecision( 2 ) << " <ca time=\"" << sender->getTime() << "\">" << endl; + for (int k = 0; k < sender->getLevelCount(); ++k) { + for (int i = 0; i < sender->getRowCount(); ++i) { + for (int j = 0; j < sender->getColumnCount(); ++j) { + if(sender->getCell(i,j,k)->isPartOfBoundary()) continue; + *out << " <cell row-index=\"" << sender->getCell(i, j, k)->getPosition()->getRowNumber() << "\"" + << " column-index=\"" << sender->getCell(i, j, k)->getPosition()->getColumnNumber() << "\"" + << " level-index=\"" << sender->getCell(i, j, k)->getPosition()->getLevelNumber() << "\"" + << ">" << endl; + + for( int l = 0; l < sender->getCell(i, j, k)->getDimension(); ++l ) { + *out << " <statevariable>" << endl; + *out << " " << sender->getCell(i, j, k)->getValue(l) << endl; + *out << " </statevariable>" << endl; + } + for( int l = 0; l < sender->getCell(i, j, k)->getDimension(); ++l ) { + *out << " <outputvariable>" << endl; + *out << " " << sender->getCell(i, j, k)->getOutputValue(l) << endl; + *out << " </outputvariable>" << endl; + } + for( int l = 0; l < sender->getCell(i, j, k)->getDimension(); ++l ) { + *out << " <inputvariable>" << endl; + *out << " " << sender->getCell(i, j, k)->getValue(l) << endl; + *out << " </inputvariable>" << endl; + } + + *out << " </cell>" << endl; + } + } + } + *out << " </ca>" << endl; + *out << endl; +} + +void CellMonitorTrace::openFile( const std::string& fileName ) +{ + out = new std::ofstream( fileName.c_str() ); + if( out == 0 || !( *out ) ) + { + // Error: cannot open file + std::cerr << "CellMonitorTrace::openFile(): cannot open file; sending output to stdout." << std::endl; + out = &std::cout; + } +} diff --git a/odemx-lite/src/base/cellular_automaton/CellVariablesContainer.cpp b/odemx-lite/src/base/cellular_automaton/CellVariablesContainer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8bbf63c3316b3cf924b40cb6cfa7e8a6098cf8c --- /dev/null +++ b/odemx-lite/src/base/cellular_automaton/CellVariablesContainer.cpp @@ -0,0 +1,109 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file CellVariablesContainer.cpp + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Implementation of class CellVariablesContainer + + \sa CellVariablesContainer.h + + \since 3.0 + */ + +#include <odemx/base/cellular_automaton/CellVariablesContainer.h> + +using namespace odemx::base; +using namespace odemx::base::cellular; +using namespace std; + +CellVariablesContainer::CellVariablesContainer(unsigned cellRows, unsigned cellColumns, unsigned cellLevel, unsigned variablesInCount, unsigned variablesOutCount, unsigned cellDimension) +: cellRows(cellRows) +, cellColumns(cellColumns) +, cellLevel(cellLevel) +, variablesInCount(variablesInCount) +, variablesOutCount(variablesOutCount) +, cellDimension(cellDimension) +{ + unsigned inputSize = cellRows*cellColumns*cellLevel*variablesInCount; + unsigned outputSize = cellRows*cellColumns*cellLevel*variablesOutCount; + unsigned stateSize = cellRows*cellColumns*cellLevel*cellDimension; + + input_values = new double[inputSize]; + state_values = new double[stateSize]; + output_values = new double[outputSize]; + + for (int i = 0; i < stateSize; ++i) { + state_values[i] = 0; + } + for (int i = 0; i < inputSize; ++i) { + input_values[i] = 0; + } + for (int i = 0; i < outputSize; ++i) { + output_values[i] = 0; + } +} + +CellVariablesContainer::~CellVariablesContainer() { + //nothing todo +} + +void CellVariablesContainer::setOutputValue(unsigned baseIndex, unsigned variableIndex, double value) { + this->output_values[baseIndex+variableIndex] = value; +} + +double CellVariablesContainer::getOutputValue(unsigned baseIndex, unsigned variableIndex) { + return this->output_values[baseIndex+variableIndex]; +} + +void CellVariablesContainer::setStateValue(unsigned baseIndex, unsigned variablesIndex, double value) { + this->state_values[baseIndex + variablesIndex] = value; +} + +double CellVariablesContainer::getStateValue(unsigned baseIndex, unsigned variablesIndex) { + return this->state_values[baseIndex + variablesIndex]; +} + +void CellVariablesContainer::setInputValue(unsigned baseIndex, unsigned variableIndex, double value) { + this->input_values[baseIndex+variableIndex] = value; +} + +double CellVariablesContainer::getInputValue(unsigned baseIndex, unsigned variableIndex) { + return this->input_values[baseIndex+variableIndex]; +} + +unsigned CellVariablesContainer::getNumberOfRows() { + return this->cellRows; +} + +unsigned CellVariablesContainer::getNumberOfColumns() { + return this->cellColumns; +} + +unsigned CellVariablesContainer::getNumberOfLevels() { + return this->cellLevel; +} + +//----------------------------------------------------------- temp function for printing values + +double* CellVariablesContainer::getOutputValues() { + return this->output_values; +} diff --git a/odemx-lite/src/base/cellular_automaton/Transition.cpp b/odemx-lite/src/base/cellular_automaton/Transition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6340aaca753f237364ee4abe1ec2771e9c9df8e9 --- /dev/null +++ b/odemx-lite/src/base/cellular_automaton/Transition.cpp @@ -0,0 +1,113 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Transition.cpp + + \author Sascha Qualitz + + \date created at 2010/01/05 + + \brief Implementation of class Cell + + \sa Cell.h + + \since 3.0 + */ + +#include <odemx/base/cellular_automaton/Transition.h> + +using namespace odemx::base; +using namespace odemx::base::cellular; +using namespace std; + +//------------------------------------------------------------------------------construction/destruction +Transition::Transition() { + +} + +Transition::~Transition() { + +} + +void Transition::setCell(Cell* cell) { + if(cell) { + this->cell = cell; + } + else { + throw new NotAssignedException("Cell", "Transition"); + } +} + +void Transition::outputFunction() { + // reimplement this + for (int i = 0; i < this->cell->getDimension(); ++i) { + cell->setOutputValue(i,cell->getValue(i)); + } +} + +double Transition::getValue(unsigned variableIndex) { + if(cell) { + return cell->getValue(variableIndex); + } + else { + throw new NotAssignedException("Cell", "Transition"); + } +} + +void Transition::setValue(unsigned variableIndex, double value) { + if(cell) { + cell->setValue(variableIndex, value); + } + else { + throw new NotAssignedException("Cell", "Transition"); + } +} + +Cell* Transition::searchNeighbor(unsigned row, unsigned column, unsigned level) { + return this->cell->searchNeighbor(row, column, level); +} + +std::map<CellPosition, Cell*, ComparePositions> Transition::calculateAlternativeNeighborhood(unsigned radius) { + // reimplement this if needed + /** + Fill a map with cells which belongs to the neighborhood of the cell. + Example: + + CellPosition position(this->cell->cellPosition->row -1, this->cell->cellPosition->column -3, this->cell->cellPosition->level -1, this->cell->monitor->getRowCount(), this->cell->monitor->getColumnCount(), this->cell->monitor->getLevelCount()) + std::map<CellPosition, Cell*, ComparePositions> map; + + map[position] = this->cell->monitor->getCell(position->row, position->column, position->level); + + One have to check that the chosen cells really exists. + */ +} + +//------------------------------------------------------------------------------NotAssignedException +NotAssignedException::NotAssignedException(const char* missingObject, const char* object) { + this->msg = "This "; + this->msg += object; + this->msg += "-Object has no "; + this->msg += missingObject; + this->msg += " assigned."; +} + +NotAssignedException::~NotAssignedException() throw() {} + +const char* NotAssignedException::what() const throw() { + return this->msg.c_str(); +} diff --git a/odemx-lite/src/base/continuous/.!4415!GSLContainer.o b/odemx-lite/src/base/continuous/.!4415!GSLContainer.o new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/odemx-lite/src/base/continuous/.!4485!GSLContainer.o b/odemx-lite/src/base/continuous/.!4485!GSLContainer.o new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/odemx-lite/src/base/continuous/.!4503!GSLContainer.o b/odemx-lite/src/base/continuous/.!4503!GSLContainer.o new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/odemx-lite/src/base/continuous/Continuous.cpp b/odemx-lite/src/base/continuous/Continuous.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbb5199b509d4ebbd70c7451ca89100988f7cc86 --- /dev/null +++ b/odemx-lite/src/base/continuous/Continuous.cpp @@ -0,0 +1,374 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Continuous.cpp + + \author Michael Fiedler + + \date created at 2009/01/02 + + \brief Implementation of class continuous + + \sa Continuous.h + + \since 3.0 + */ + +#include <odemx/base/continuous/Continuous.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Monitor.h> +#include <odemx/base/TypeDefs.h> +#include <fstream> +#include <iomanip> +#include <iostream> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +//----------------------------------------------------------------construction/destruction +continuous::Continuous::Continuous(Simulation& sim, const data::Label& label, int dimension) +: Producer( sim, label ) +, monitor(0) +, dimension(dimension) +, baseIndex(0) +{ + //ODEMX_TRACE << log( "create with sim" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, Create(this)); +} + +continuous::Continuous::Continuous(Simulation& sim, const data::Label& label, Monitor* monitor, int dimension, ODEObject* equation) +: Producer( sim, label ) +, monitor(0) +, dimension(dimension) +, baseIndex(0) +{ + setMonitor(monitor); + if(equation != 0) addODE(equation); + + //ODEMX_TRACE << log( "create with sim, monitor and equation" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, Create(this)); +} + +continuous::Continuous::Continuous(Simulation& sim, const data::Label& label, Monitor* monitor, int dimension, std::list<ODEObject*> equationList) +: Producer( sim, label ) +, monitor(0) +, dimension(dimension) +, baseIndex(0) +{ + setMonitor(monitor); + addODEList(equationList); + + //ODEMX_TRACE << log( "create with sim, monitor and a list of equations" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, Create(this)); +} + +Continuous::~Continuous() { + //ODEMX_TRACE << log( "destroy" ); +} + +//--------------------------------------------------------------handle responsible Monitor +void Continuous::setMonitor(Monitor *monitor) { + if (this->monitor != 0) { //remove from old + this->monitor->removeContinuous(this); //all actions are implemented in Monitor + } + + if (monitor != 0) { //add to new + monitor->addContinuous(this); //all actions are implemented in Monitor + } + + //ODEMX_TRACE << log( "set new monitor" ).scope( typeid(Continuous) ); + + // observer + ODEMX_OBS(ContinuousObserver, SetMonitor(this, monitor)); +} + +Monitor* Continuous::getMonitor() { + return monitor; +} + +//---------------------------------------------------------------handle active equations +void Continuous::addODEList(std::list<ODEObject*> equationList) { + std::list<ODEObject*>::iterator iter; + for (iter = equationList.begin(); iter != equationList.end(); iter++) + addODE(*iter); +} + +void Continuous::addODE(ODEObject *equation) { + if (equation != 0) { //only add real objects + if (equation->continuous != 0) { //delete from old Continuous + equation->continuous->removeODE(equation); + } + //add to this Continuous + equation->continuous = this; + this->equations.push_back(equation); + //tell monitor that system changed + this->setChanged(); + + //ODEMX_TRACE << log( "add ODE" ).scope( typeid(Continuous) ); + + // observer + //ODEMX_OBS(ContinuousObserver, AddODE(this, equation)); + } +} + +void Continuous::removeODE(ODEObject *equation) { + //go to position.. + std::list<ODEObject*>::iterator iter = find(this->equations.begin(), + this->equations.end(), equation); + //..and delete + if (*iter == equation) { + this->equations.erase(iter); + } + equation->continuous = 0; + //tell monitor that system changed + this->setChanged(); + + //ODEMX_TRACE << log( "remove ODE" ).scope( typeid(Continuous) ); + + // observer + //ODEMX_OBS(ContinuousObserver, RemoveODE(this, equation)); +} + +//--------------------------------------------------------------------------------stuff +int Continuous::getDimension() { + return dimension; +} + +void Continuous::setChanged() { + if (monitor) monitor->setChanged(); +} + +//-----------------------------------------------------handle values between integration +void Continuous::setValue(int i, double value) { + if (monitor != 0 && monitor->variables != 0) { + monitor->variables->setVariable(this->baseIndex + i, value); + //tell monitor that system changed since init value changed + this->setChanged(); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +double Continuous::getValue(int i) { + if (monitor != 0) { + return monitor->variables->getVariable(this->baseIndex + i); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +//---------------------------------------------------------handle values in integration +double Continuous::getValueForDerivative(int i) { + if (monitor != 0) { + return monitor->variables->getValue(this->baseIndex + i); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +void Continuous::setDerivative(int i, double value) { + if (monitor != 0) { + monitor->variables->addToDerivative(this->baseIndex + i, value); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +double Continuous::getDerivative(int i) { + if (monitor != 0) { + return monitor->variables->getDerivative(this->baseIndex + i); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +void Continuous::setJacobi(int i, int j, double value) { + if (monitor != 0) { + monitor->variables->addToJacobi(this->baseIndex + i, this->baseIndex + j, value); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +double Continuous::getJacobi(int i, int j) { + if (monitor != 0) { + return monitor->variables->getJacobi(this->baseIndex + i, this->baseIndex + j); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +void Continuous::setJacobi(int i, Continuous* continuous, int j, double value) { + if (monitor != 0) { + monitor->variables->addToJacobi(this->baseIndex + i, continuous->baseIndex + j, value); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +double Continuous::getJacobi(int i, Continuous* continuous, int j) { + if (monitor != 0) { + return monitor->variables->getJacobi(this->baseIndex + i, continuous->baseIndex + j); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +void Continuous::setDfDt(int i, double value) { + if (monitor != 0) { + monitor->variables->addToDfDt(this->baseIndex + i, value); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +double Continuous::getDfDt(int i) { + if (monitor != 0) { + return monitor->variables->getDfDt(this->baseIndex + i); + } else { + //throw NotAssignedException for missing Monitor + throw new NotAssignedException("Monitor", "Continuous"); + } +} + +void Continuous::notifyValidState() { + //observers + ODEMX_OBS(ContinuousObserver, NewValidState(this)); +} + +ContinuousTrace::ContinuousTrace(Continuous* contu, const string & fileName) +: out(0), + firstTime(true), + fileName(fileName), + continuous(contu) +{ +#ifdef ODEMX_USE_OBSERVATION + if( contu != 0 ) + { + contu->data::Observable< ContinuousObserver >::addObserver( this ); + } +#endif + + if( ! fileName.empty() ) + { + openFile( fileName ); + } + else if( contu != 0 ) + { + std::string fn = contu->getLabel(); + fn += "_trace.txt"; + openFile( fn ); + } +} + +ContinuousTrace::~ContinuousTrace() +{ + if( out == 0 || out == &std::cout ) + { + return; + } + + static_cast< std::ofstream* >( out )->close(); + delete out; +} + +void ContinuousTrace::onNewValidState( Continuous* sender ) +{ + using namespace std; + + assert( sender != 0 ); + + if( firstTime ) + { + if( out == 0 ) + { + std::string fn = fileName; + fn += "_trace.txt"; + openFile( fn ); + } + + *out << endl; + *out << setw(60) << "T R A C E F I L E F O R " << sender->getLabel() << " managed by monitor " << sender->getMonitor()->getLabel() << endl << endl; + *out << setw(13) << "Time"; + *out << setw(13) << "Steplength"; + *out << setw(13) << "Error"; + + for( int i = 0; i < continuous->getDimension(); ++i ) { + *out << setw(15) << "state[" << i << "]"; + } + + for( int i = 0; i < continuous->getDimension(); ++i ) { + *out << setw(15) << "rate[" << i << "]"; + } + + *out << endl; + + firstTime=false; + } + + ( *out ).setf( std::ios::showpoint ); + ( *out ).setf( std::ios::fixed ); + *out << setw( 13 ) << setprecision( 10 ) << sender->getMonitor()->getActualInternalTime(); + *out << setw( 14 ) << setprecision( 10 ) << sender->getMonitor()->getODESolver()->getStepLength(); + *out << setw( 14 ) << setprecision( 10 ) << sender->getMonitor()->getODESolver()->getErrorLimit(); + + //State values + for( int i = 0; i < sender->getDimension(); ++i ) { + *out << setw( 18 ) << setprecision( 10 ) << sender->getValue(i); + } + + //rate values + for( int i = 0; i < sender->getDimension(); ++i ) { + *out << setw( 18 ) << setprecision( 10 ) << sender->getDerivative(i); + } + + *out << endl; +} + +void ContinuousTrace::openFile( const std::string& fileName ) +{ + out = new std::ofstream( fileName.c_str() ); + if( out == 0 || !( *out ) ) + { + // Error: cannot open file + std::cerr << "MonitorTrace::openFile(): cannot open file; sending output to stdout." << std::endl; + out = &std::cout; + } +} + +#endif /* ODEMX_USE_CONTINUOUS */ + diff --git a/odemx-lite/src/base/continuous/DfDt.cpp b/odemx-lite/src/base/continuous/DfDt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..375a27e45ca404a4407c850c3ea624bf2a1c6165 --- /dev/null +++ b/odemx-lite/src/base/continuous/DfDt.cpp @@ -0,0 +1,96 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file DfDt.cpp + + \author Sascha Qualitz + + \date created at 2009/10/26 + + \brief Implementation of DfDt + + \sa DfDt.h + + \since 3.0 +*/ + +#include <odemx/base/continuous/DfDt.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Continuous.h> +#include <odemx/base/continuous/Monitor.h> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +DfDt::DfDt() +: continuous(0), + index_(0) +{} + +DfDt::DfDt(Continuous* continuous) +: continuous(continuous), + index_(0) +{} + +DfDt::~DfDt() { + // nothing todo! +} + +DfDt& DfDt::operator =(const double value) { + setValue(value); + return *this; +} + +DfDt& DfDt::operator [](const unsigned i) { + if (continuous != 0) { + if(i > continuous->getDimension()-1) + throw std::out_of_range("The index in an object of type DfDt is out of bounds"); + + index_ = i; + + return *this; + } else + throw new NotAssignedException("Continuous", "DfDt"); +} + +void DfDt::setContinuous(Continuous* continuous) { + if (continuous != 0) { + this->continuous = continuous; + } else + throw new NotAssignedException("Continuous", "DfDt"); +} + +double DfDt::getValue() const{ + if (continuous != 0) { + return continuous->getDfDt(index_); + } else + throw new NotAssignedException("Continuous", "DfDt"); +} + +void DfDt::setValue(double value) { + if (continuous != 0) { + continuous->setDfDt(index_, value); + } else + throw new NotAssignedException("Continuous", "DfDt"); +} + +#endif /* ODEMX_USE_CONTINUOUS */ + diff --git a/odemx-lite/src/base/continuous/GSLContainer.o b/odemx-lite/src/base/continuous/GSLContainer.o new file mode 100644 index 0000000000000000000000000000000000000000..1eda7c2d48cb56a26965e455a7f98a7e64eb718a Binary files /dev/null and b/odemx-lite/src/base/continuous/GSLContainer.o differ diff --git a/odemx-lite/src/base/continuous/JacobiMatrix.cpp b/odemx-lite/src/base/continuous/JacobiMatrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46c6e36868183166fc1ab15ca1b404e70b889e32 --- /dev/null +++ b/odemx-lite/src/base/continuous/JacobiMatrix.cpp @@ -0,0 +1,128 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file JacobiMatrix.cpp + + \author Sascha Qualitz + + \date created at 2009/10/26 + + \brief Implementation of JacobiMatrix + + \sa JacobiMatrix.h + + \since 3.0 +*/ + +#include <odemx/base/continuous/JacobiMatrix.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Continuous.h> +#include <odemx/base/continuous/Monitor.h> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +JacobiMatrix::JacobiMatrix() +: continuous(0), + otherContinuous(0), + row_(0), + column_(0) +{} + +JacobiMatrix::JacobiMatrix(Continuous* continuous) +: continuous(continuous), + otherContinuous(0), + row_(0), + column_(0) +{} + +JacobiMatrix::JacobiMatrix(Continuous* continuous, Continuous* otherContinuous) +: continuous(continuous), + otherContinuous(otherContinuous), + row_(0), + column_(0) +{} + +JacobiMatrix::~JacobiMatrix() { + // TODO Auto-generated destructor stub +} + +double JacobiMatrix::getValue() const { + if(continuous != 0 || otherContinuous != 0) { + if(otherContinuous != 0) + return continuous->getJacobi(row_, otherContinuous, column_); + else + return continuous->getJacobi(row_, column_); + } else + throw new NotAssignedException("Continuous", "JacobiMatrix"); + +} + +void JacobiMatrix::setValue(double value) { + if(continuous != 0 || otherContinuous != 0) { + if(otherContinuous != 0) + continuous->setJacobi(row_, otherContinuous, column_, value); + else + continuous->setJacobi(row_, column_, value); + } else + throw new NotAssignedException("Continuous", "JacobiMatrix"); +} + +JacobiMatrix& JacobiMatrix::operator =(const double value) { + setValue(value); + return *this; +} + +JacobiMatrix& JacobiMatrix::operator ()(const unsigned row, const unsigned column) { + if(continuous != 0 || otherContinuous != 0) { + if(otherContinuous != 0) { + if(row > continuous->getDimension()-1 || column > otherContinuous->getDimension()-1) + throw std::out_of_range("An index in an object of type JacobiMatrix is out of bounds"); + } else { + if(row > continuous->getDimension()-1 || column > continuous->getDimension()-1) + throw std::out_of_range("An index in an object of type JacobiMatrix is out of bounds"); + } + + row_ = row; + column_ = column; + + return *this; + } else + throw new NotAssignedException("Continuous", "JacobiMatrix"); +} + +void JacobiMatrix::setContinuous(Continuous* continuous) { + if(continuous != 0) { + this->continuous = continuous; + } else + throw new NotAssignedException("Continuous", "JacobiMatrix"); +} + +void JacobiMatrix::setContinuous(Continuous* continuous, Continuous* otherContinuous) { + if(continuous != 0 || otherContinuous != 0) { + this->continuous = continuous; + this->otherContinuous = otherContinuous; + } else + throw new NotAssignedException("Continuous", "JacobiMatrix"); +} + + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/Monitor.cpp b/odemx-lite/src/base/continuous/Monitor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edb0c18fa4e62a7f5545e4034f18e7ab29fc2d63 --- /dev/null +++ b/odemx-lite/src/base/continuous/Monitor.cpp @@ -0,0 +1,589 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Monitor.cpp + + \author Michael Fiedler + + \date created at 2009/01/02 + + \brief Implementation of class Monitor + + \sa Monitor.h + + \since 3.0 +*/ + +#include <odemx/base/continuous/Monitor.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/Scheduler.h> +#include <odemx/base/Simulation.h> +#include <typeinfo> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +#define MIN_MONITOR_ENLARGE( a ) a > 10 ? a : 10 + +//----------------------------------------------------------------------------------construction/destruction + +Monitor::Monitor(Simulation& s, const data::Label& label, int variablesArraySize, ODESolver* solver, MonitorObserver* o) +: Process(s, label, o), + workingMode(intervall), + searchMode(linearization), + variablesArraySize(variablesArraySize), + variablesCount(0), + variables(0), + internalTime(0), + timeLimit(0), + timeLimitSet(false), + hasToStop(false), + diffTime(0.0), + changed(true) +{ + setODESolver(solver); + + ODEMX_TRACE << log( "create with sim and solver" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, Create(this)); +} + +Monitor::~Monitor(){ + if (variables) { + delete variables; + } + + ODEMX_TRACE << log( "destroy" ).scope( typeid(Monitor) ); +} + +//------------------------------------------------------------------------------stop monitor +void Monitor::setTimeLimit(SimTime time) { + timeLimitSet = true; + timeLimit = time; +} + +bool Monitor::getTimeLimit(SimTime* time) { + if (timeLimitSet) { + *time = timeLimit; + return true; + } else { + return false; + } +} + +void Monitor::removeTimeLimit() { + timeLimitSet = false; +} + +void Monitor::stop() { + hasToStop = true; + + ODEMX_TRACE << log( "Monitor stops" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, Stop(this)); +} + +//-------------------------------------------------------------------------------eval system +void Monitor::evalF(double time) { + this->variables->nullDerivatives(); + SimTime evalTime = (SimTime)(internalTime + time); + std::list<Continuous*>::iterator iter; + std::list<ODEObject*>::iterator iter2; + + for (iter = this->continuousList.begin(); iter != this->continuousList.end(); iter++) + for (iter2 = (*iter)->equations.begin(); iter2 != (*iter)->equations.end(); iter2++) + (*iter2)->derivates(evalTime); +} + +void Monitor::evalJacobian(double time) { + this->variables->nullJacobi(); + this->variables->nullDfDt(); + SimTime evalTime = (SimTime)(internalTime + time); + std::list<Continuous*>::iterator iter; + std::list<ODEObject*>::iterator iter2; + for (iter = this->continuousList.begin(); iter != this->continuousList.end(); iter++) + for (iter2 = (*iter)->equations.begin(); iter2 != (*iter)->equations.end(); iter2++) + (*iter2)->jacobi(evalTime); +} + +//--------------------------------------------------------------------------handle used solver +void Monitor::setODESolver(ODESolver *solver) { + if (solver) { + if (solver->monitor) { + solver->monitor->setODESolver(0); + } + + VariableContainer *newVariables = solver->getVariableContainer(variablesArraySize); + int lv; //loop variable + if (variables) { + //copy from old container to new (only variables the rest depend on this) + for (lv = 0; lv < variablesCount; lv++) + newVariables->setVariable(lv, variables->getVariable(lv)); + //after copying clean old + delete variables; + } + variables = newVariables; + this->solver = solver; + solver->monitor = this; + + ODEMX_TRACE << log( "set solver" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, SetODESolver(this, solver)); + + } else { + this->solver = 0; + //keep variables to keep state + } + + setChanged(); +} + +ODESolver* Monitor::getODESolver() { + return solver; +} + +//-----------------------------------------------------------add/remove Continuous and StateEvent +void Monitor::addContinuous(Continuous *continuous) { + if (continuous != 0) { //only add real objects + if (continuous->monitor != 0) { //delete from old Monitor + continuous->monitor->removeContinuous(continuous); + } + //add to this Monitor + continuous->monitor = this; + continuous->baseIndex = this->variablesCount; + this->continuousList.push_back(continuous); + this->variablesCount += continuous->getDimension(); + int diffSize = this->variablesCount - this->variablesArraySize; + if (diffSize > 0) { + this->variablesArraySize += MIN_MONITOR_ENLARGE( diffSize ); + if (variables) + variables->adaptSizeTo(this->variablesArraySize); + } + + ODEMX_TRACE << log( "add continuous object" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, AddContinuous(this, continuous)); + } + setChanged(); +} + +void Monitor::removeContinuous(Continuous *continuous) { + //go to position.. + std::list<Continuous*>::iterator iter = find(this->continuousList.begin(), + this->continuousList.end(), continuous); + //..and delete + if (*iter == continuous) { + this->continuousList.erase(iter); + + ODEMX_TRACE << log( "remove continuous object" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, RemoveContinuous(this, continuous)); + } + continuous->monitor = 0; + setChanged(); +} + +void Monitor::addStateEvent(StateEvent *stateEvent) { + if (stateEvent) { //only add real objects + if (stateEvent->monitor) { //delete from old Monitor + stateEvent->monitor->removeStateEvent(stateEvent); + } + //add to this Monitor + stateEvent->monitor = this; + this->stateEvents.push_back(stateEvent); + if (stateEvent->condition(getActualInternalTime())) { + //condition holds so trigger action + stateEvent->action(); + } + + ODEMX_TRACE << log( "add StateEvent" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS( MonitorObserver, AddStateEvent( this, stateEvent ) ); + + } +} + +void Monitor::removeStateEvent(StateEvent *stateEvent) { + //go to position.. + std::list<StateEvent*>::iterator iter = find(this->stateEvents.begin(), + this->stateEvents.end(), stateEvent); + //..and delete + if (*iter == stateEvent) { + this->stateEvents.erase(iter); + + ODEMX_TRACE << log( "remove StateEvent" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS( MonitorObserver, RemoveStateEvent( this, stateEvent ) ); + } + stateEvent->monitor = 0; +} + +//-----------------------------------------------------------add/remove process from synchronisation +void Monitor::addProcessToWaitList(Process *process) { + if (process) { //only add real objects + waitForProcesses.push_back(process); + + ODEMX_TRACE << log( "add process to list waitForProcesses" ).detail( "process", process ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, AddProcessToWaitList(this, process)); + } +} + +void Monitor::removeProcessFromWaitList(Process *process) { + //go to position + std::list<Process*>::iterator iter = find(waitForProcesses.begin(), + waitForProcesses.end(), process); + //..and delete + if (*iter == process) { + waitForProcesses.erase(iter); + + ODEMX_TRACE << log( "remove process from list waitForProcesses" ).detail( "process", process ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, RemoveProcessFromWaitList(this, process)); + } +} + +//-----------------------------------------------------------------------------manage internal time +void Monitor::setInternalTime(SimTime time) { + setChanged(); + internalTime = time; + diffTime = 0.0; + //check StateEvents to be sure conditions are false in this state or trigger action + std::list<StateEvent*>::iterator iter; + for (iter = this->stateEvents.begin(); iter != this->stateEvents.end(); iter++) { + if ((*iter)->condition(time)) { + (*iter)->action(); + } + } + + ODEMX_TRACE << log( "internal time has changed" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, SetInternalTime(this, time)); +} + +SimTime Monitor::getInternalTime() { + return internalTime; +} + +SimTime Monitor::getActualInternalTime() { + return (SimTime)(internalTime + diffTime); +} + +void Monitor::adaptInternalTime() { + setChanged(); + internalTime = (SimTime)(internalTime + diffTime); + diffTime = 0.0; + + ODEMX_TRACE << log( "adapted internal time to actual time" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, AdaptInternalTime(this, internalTime)); +} + +SimTime Monitor::getStepTimeLimit() { + SimTime limit = waitForProcesses.front()->getExecutionTime(); + + for (std::list<Process*>::iterator iter = waitForProcesses.begin(); iter != waitForProcesses.end(); ++iter) { + Process* current = *iter; + SimTime execTime = current->getExecutionTime(); + if(current->isScheduled() && execTime < limit) { + limit = execTime; + } + } + + waitForProcesses.pop_front(); + + return limit; +} + +//----------------------------------------------------------------------------main and integration +int Monitor::main() { + while (!hasToStop && (!timeLimitSet || getActualInternalTime() < timeLimit) && solver != 0) { + SimTime limit = timeLimit; + if (!waitForProcesses.empty()) { + limit = getStepTimeLimit(); + if (timeLimitSet) { + limit = limit < timeLimit ? limit : timeLimit; + } + integrateUntil(limit); + } else if (timeLimitSet) { + integrateUntil(limit); + } else if (!stateEvents.empty()) { //only stops if an stateEvent occurs + integrate(); + } else { + //no limit for integration intervall, would result in infinite long working + hasToStop = true; + } + holdUntil(getActualInternalTime()); + } + return 0; +} + +void Monitor::integrate() { + + if( getProcessState() != Process::CURRENT ) + { + error << log( "Monitor::integrate(): object is not the current process" ) + .scope( typeid(Monitor) ); + } + + if (solver) { + if (changed == true) { + solver->init(); + changed = false; + } + + ODEMX_TRACE << log( "begin integrate" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, BeginIntegrate(this)); + + bool testStateEvents = !stateEvents.empty(); //only to testing if necessary + double old_diffTime, *old_variable_values, old_maxStep = solver->maxStep; + int lv; //loop variable + std::list<StateEvent*>::iterator iter; + if (testStateEvents) { + //init for first step of while loop + old_diffTime = diffTime; + old_variable_values = new double[ variablesCount ]; + for (lv = 0; lv < variablesCount; lv++) + old_variable_values[lv] = variables->getVariable(lv); + } + while (testStateEvents) { //avoid infite loop + // observer + for (std::list<Continuous*>::iterator observerIter = this->continuousList.begin(); observerIter != this->continuousList.end(); ++observerIter) { + (*observerIter)->notifyValidState(); + } + + //make an integration step + solver->makeStep(diffTime); + diffTime += solver->getStepLength(); + //test state events + for (iter = this->stateEvents.begin(); iter != this->stateEvents.end(); iter++) { + if ((*iter)->condition(getActualInternalTime())) { + //search point of change and trigger action + searchStateEvent(old_diffTime, old_variable_values); + //stop integration + break; + } + } + //init for next step of while loop + old_diffTime = diffTime; + for (lv = 0; lv < variablesCount; lv++) + old_variable_values[lv] = variables->getVariable(lv); + + if (workingMode == stepwise) break; + } + solver->setStepLength(solver->minStep, old_maxStep); //correct stepping limits to old + if (testStateEvents) { + delete[] old_variable_values; + } + + ODEMX_TRACE << log( "end integrate" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, EndIntegrate(this)); + + } else { + //todo throw exception no solver assigned + } +} + +void Monitor::integrateUntil(SimTime time) { + + if( getProcessState() != Process::CURRENT ) + { + error << log( "Monitor::integrateUntil(): object is not the current process" ) + .scope( typeid(Monitor) ); + } + + if (solver) { + double expectedDiff = (double)(time - internalTime); + if (changed == true) { + solver->init(); + changed = false; + } + + ODEMX_TRACE << log( "begin integrate until" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, BeginIntegrateUntil(this)); + + bool testStateEvents = !stateEvents.empty(); //only to testing if necessary + double old_diffTime, *old_variable_values, old_maxStep = solver->maxStep; + int lv; //loop variable + std::list<StateEvent*>::iterator iter; + if (testStateEvents) { + //init for first step of while loop + old_diffTime = diffTime; + old_variable_values = new double[ variablesCount ]; + for (lv = 0; lv < variablesCount; lv++) + old_variable_values[lv] = variables->getVariable(lv); + } + + while (diffTime <= expectedDiff) { + if (expectedDiff - diffTime <= solver->maxStep) { //make sure intergation does not exceed the limit + solver->setStepLength(solver->minStep, expectedDiff - diffTime); + } + + // observer + for (std::list<Continuous*>::iterator observerIter = this->continuousList.begin(); observerIter != this->continuousList.end(); ++observerIter) { + (*observerIter)->notifyValidState(); + } + + //make an integration step + solver->makeStep(diffTime); + diffTime += solver->getStepLength(); + if (testStateEvents) { + //test state events + for (iter = this->stateEvents.begin(); iter != this->stateEvents.end(); iter++) { + if ((*iter)->condition(getActualInternalTime())) { + //search point of change and trigger action + searchStateEvent(old_diffTime, old_variable_values); + //stop integration + break; + } + } + //init for next step of while loop + old_diffTime = diffTime; + for (lv = 0; lv < variablesCount; lv++) + old_variable_values[lv] = variables->getVariable(lv); + } + if (workingMode == stepwise) break; + } + solver->setStepLength(solver->minStep, old_maxStep); //correct stepping limits to old + if (testStateEvents) { + delete[] old_variable_values; + } + + ODEMX_TRACE << log( "end integrate until" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, EndIntegrateUntil(this)); + + } else { + //todo throw exception no solver assigned + } +} + +//------------------------------------------------------------------------------------------search occurance of StateEvents +void Monitor::searchStateEvent(double old_diffTime, double *old_variable_values) { + double left = old_diffTime; //left time bound + double right = diffTime; //right time bound + double precision = solver->minStep; //determines how precise the search should be + double half = (right - left) / 2; + bool isLeft; //is true if at observed time at least one condition is true + std::list<StateEvent*>::iterator iter; + int lv; // loop variable + //search time of first StateEvent + switch (searchMode) { + case direct: { + while (right-left >= precision) { + for (lv = 0; lv < variablesCount; lv++) //set initial condition for new shorter step at left + variables->setVariable(lv, old_variable_values[lv]); + solver->setStepLength(half, half); //set stepLength to be half + //errorLimit is proven by greater step done before this function is called + solver->makeStep(left); + //check conditions + isLeft = false; + for (iter = this->stateEvents.begin(); iter != this->stateEvents.end(); iter++) { + if ((*iter)->condition((SimTime)(internalTime + left + half))) + isLeft = true; + } + //adapt search intervall + if (isLeft == true) { + right = left + half; + } else { + left += half; + for (lv = 0; lv < variablesCount; lv++) + old_variable_values[lv] = variables->getVariable(lv); + } + half = (right - left) / 2; + } + //correct diffTime + diffTime = right; + } break; + case linearization: + default: { + double *right_values = new double[ variablesCount ]; + for (lv = 0; lv < variablesCount; lv++) + right_values[lv] = variables->getVariable(lv); + while (right-left >= precision) { + for (lv = 0; lv < variablesCount; lv++) { //set linear interpolation value at half + variables->setVariable(lv, (old_variable_values[lv] + right_values[lv]) / 2); + } + //check conditions + isLeft = false; + for (iter = this->stateEvents.begin(); iter != this->stateEvents.end(); iter++) { + if ((*iter)->condition((SimTime)(internalTime + left + half))) + isLeft = true; + } + //adapt search intervall + if (isLeft == true) { + right = left + half; + for (lv = 0; lv < variablesCount; lv++) + right_values[lv] = variables->getVariable(lv); + } else { + left += half; + for (lv = 0; lv < variablesCount; lv++) + old_variable_values[lv] = variables->getVariable(lv); + } + half = (right - left) / 2; + } + delete[] right_values; + //correct diffTime + diffTime = right; + } + } + //trigger events + for (iter = this->stateEvents.begin(); iter != this->stateEvents.end(); iter++) { + if ((*iter)->condition(getActualInternalTime())) { + (*iter)->action(); + removeStateEvent((*iter)); + } + } +} + +//-------------------------------------------------------------------------------------------------others +void Monitor::setSearchMode(SearchModes mode) { + searchMode = mode; +} + +void Monitor::setChanged() { + changed = true; + + ODEMX_TRACE << log( "setChanged: system changed" ).scope( typeid(Monitor) ); + + // observer + ODEMX_OBS(MonitorObserver, SetChanged(this)); +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/ODEObject.cpp b/odemx-lite/src/base/continuous/ODEObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ddc31e32765f78f07e9f8490ca584e9dc60a749 --- /dev/null +++ b/odemx-lite/src/base/continuous/ODEObject.cpp @@ -0,0 +1,83 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ODEObject.cpp + + \author Michael Fiedler + + \date created at 2009/01/02 + + \brief Implementation of classes in ODEObject.h + + \sa ODEObject.h + + \since 3.0 + */ + +#include <odemx/base/continuous/ODEObject.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Continuous.h> +#include <odemx/base/continuous/JacobiMatrix.h> +#include <odemx/base/continuous/DfDt.h> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +//--------------------------------------------------------------handle corresponding Continuous instance +void ODEObject::setContinuous(Continuous *continuous) { + if (this->continuous != 0) { //remove from old + this->continuous->removeODE(this); //all actions are implemented in Continuous + } + if (continuous != 0) { //add to new + continuous->addODE(this); //all actions are implemented in Continuous + } +} + +Continuous* ODEObject::getContinuous() { + return continuous; +} + +void ODEObject::derivates(SimTime time) +{ + derivatives_(time); +} + +void ODEObject::jacobi(SimTime time) +{ + jacobi_(time); +} + +//------------------------------------------------------------------------------NotAssignedException +NotAssignedException::NotAssignedException(const char* missingObject, const char* object) { + this->msg = "This "; + this->msg += object; + this->msg += "-Object has no "; + this->msg += missingObject; + this->msg += " assigned."; +} + +NotAssignedException::~NotAssignedException() throw() {} + +const char* NotAssignedException::what() const throw() { + return this->msg.c_str(); +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/ODESolver.cpp b/odemx-lite/src/base/continuous/ODESolver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8192dda683fe86a05b43669fdc57cc91a804d28d --- /dev/null +++ b/odemx-lite/src/base/continuous/ODESolver.cpp @@ -0,0 +1,102 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ODESolver.cpp + + \author Michael Fiedler + + \date created at 2009/01/02 + + \brief Implementation of class ODESolver + + \sa ODESolver.h + + \since 3.0 +*/ + +#include <odemx/base/continuous/ODESolver.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Monitor.h> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +//--------------------------------------------------------------------dConstruction +ODESolver::ODESolver(Simulation& sim) : Producer(sim, "ODESolver") { + //nothing todo +} +//--------------------------------------------------------------------destruction +ODESolver::~ODESolver() { + //nothing todo +} + +//--------------------------------------------------------evaluate monitor system +//this is to pass access to these function to subclasses +void ODESolver::evalF(double time) { + monitor->evalF(time); +} + +void ODESolver::evalJacobian(double time) { + monitor->evalJacobian(time); +} + +//-------------------------------------------------------handle assigned monitor +void ODESolver::setMonitor(Monitor* monitor) { + if (monitor) { + monitor->setODESolver(this); + } +} + +Monitor* ODESolver::getMonitor() { + return monitor; +} + +//------------------------------------------------------get variables of monitor +VariableContainer* ODESolver::getVariableContainerOfMonitor() { + return monitor->variables; +} + +//--------------------------------------------------------integration Parameters +void ODESolver::setErrorLimit(double maxError) { + if (maxError > 0) { + errorLimit = maxError; + } +} + +double ODESolver::getErrorLimit() { + return this->errorLimit; +} + +void ODESolver::setErrorType(ErrorType type) { + errorType = type; +} + +void ODESolver::setStepLength(double min, double max) { + if (min > 0) minStep = min; + if (max > 0) maxStep = max; + if (maxStep < minStep) maxStep = minStep; +} + +double ODESolver::getStepLength() { + return lastStep; +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/Rate.cpp b/odemx-lite/src/base/continuous/Rate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0dc2e49ac4e9476b1c2182c01cf5f9d8c8cbd94 --- /dev/null +++ b/odemx-lite/src/base/continuous/Rate.cpp @@ -0,0 +1,95 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Rate.cpp + + \author Sascha Qualitz + + \date created at 2009/10/26 + + \brief Implementation of Rate + + \sa Rate.h + + \since 3.0 +*/ + +#include <odemx/base/continuous/Rate.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/State.h> +#include <odemx/base/continuous/Continuous.h> +#include <odemx/base/continuous/Monitor.h> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +Rate::Rate() +: continuous(0), + index_(0) +{} + +Rate::Rate(Continuous* continuous) +: continuous(continuous), + index_(0) +{} + +Rate::~Rate() { + // nothing todo!! +} + +void Rate::setContinuous(Continuous* continuous) { + if (continuous != 0) { + this->continuous = continuous; + } else + throw new NotAssignedException("Continuous", "Rate"); +} + +void Rate::setValue(double value) { + if (continuous != 0) { + continuous->setDerivative(index_, value); + } else + throw new NotAssignedException("Continuous", "Rate"); +} + +double Rate::getValue() { + if (continuous != 0) + return continuous->getDerivative(index_); + + throw new NotAssignedException("Continuous", "Rate"); +} + +Rate& Rate::operator =(const double value) { + setValue(value); + return *this; +} + +Rate& Rate::operator [](const unsigned i) { + if (continuous != 0) { + if(i > continuous->getDimension()-1) + throw std::out_of_range("The index in an object of type Rate is out of bounds"); + index_ = i; + + return *this; + } else + throw new NotAssignedException("Continuous", "Rate"); +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/State.cpp b/odemx-lite/src/base/continuous/State.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7790b81b55a6db52e27c8a8bbbca211bcc479cd --- /dev/null +++ b/odemx-lite/src/base/continuous/State.cpp @@ -0,0 +1,95 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file State.cpp + + \author Sascha Qualitz + + \date created at 2009/10/26 + + \brief Implementation of State + + \sa State.h + + \since 3.0 +*/ + +#include <odemx/base/continuous/State.h> + +#ifdef ODEMX_USE_CONTINUOUS + +#include <odemx/base/continuous/Continuous.h> +#include <odemx/base/continuous/Monitor.h> +#include <odemx/base/continuous/ODEObject.h> + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +State::State() +: continuous(0), + index_(0) +{} + +State::State(Continuous* continuous) +: continuous(continuous), + index_(0) +{} + +State::~State() { + // nothing todo!! +} + +void State::setContinuous(Continuous* continuous) { + if (continuous != 0) { + this->continuous = continuous; + } else + throw new NotAssignedException("Continuous", "State"); +} + +State& State::operator =(const double value) { + setValue(value); + return *this; +} + +double State::getValue() const{ + if (continuous != 0) { + return continuous->getValueForDerivative(index_); + } else + throw new NotAssignedException("Continuous", "State"); +} + +void State::setValue(double value) { + if (continuous != 0) { + continuous->setValue(index_, value); + } else + throw new NotAssignedException("Continuous", "State"); +} + +State& State::operator [](const unsigned i) { + if (continuous != 0) { + if(i > continuous->getDimension()-1) + throw std::out_of_range("The index in an object of type State is out of bounds"); + index_ = i; + + return *this; + } else + throw new NotAssignedException("Continuous", "State"); +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/StateEvent.cpp b/odemx-lite/src/base/continuous/StateEvent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc6e3221633f4808bb518b2eca276364117ab04c --- /dev/null +++ b/odemx-lite/src/base/continuous/StateEvent.cpp @@ -0,0 +1,53 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file StateEvent.cpp + + \author Michael Fiedler + + \date created at 2009/01/02 + + \brief Implementation of class StateEvent + + \sa StateEvent.h + + \since 3.0 + */ + +#include <odemx/base/continuous/StateEvent.h> + +#ifdef ODEMX_USE_CONTINUOUS + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +StateEvent::~StateEvent() { + +} + +//-----------------------------------------------------------handle assigned monitor +void StateEvent::setMonitor(Monitor *monitor) { + monitor->addStateEvent(this); +} + +Monitor* StateEvent::getMonitor() { + return monitor; +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/continuous/VariableContainer.cpp b/odemx-lite/src/base/continuous/VariableContainer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f481bd4cc87470ba40068434d470d6deb387dea7 --- /dev/null +++ b/odemx-lite/src/base/continuous/VariableContainer.cpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004, 2007 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \fileVariableContainer.cpp + + \author Michael Fiedler + + \date created at 2009/01/02 + + \brief Implementation of class VariableContainer + + \sa VariableContainer.h + + \since 3.0 + */ + +#include <odemx/base/continuous/VariableContainer.h> + +#ifdef ODEMX_USE_CONTINUOUS + +using namespace odemx::base; +using namespace odemx::base::continuous; +using namespace std; + +VariableContainer::~VariableContainer() { + //nothing todo +} + +#endif /* ODEMX_USE_CONTINUOUS */ diff --git a/odemx-lite/src/base/control/ControlBase.cpp b/odemx-lite/src/base/control/ControlBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e08ffe5141f8a55f735d9a060de192849a66d280 --- /dev/null +++ b/odemx-lite/src/base/control/ControlBase.cpp @@ -0,0 +1,44 @@ +#include <odemx/base/control/ControlBase.h> +#include <odemx/base/Process.h> +#include <iostream> + + +namespace odemx { +namespace base { + +void ControlBase::signal() +{ + for(auto process: waitingProcesses_) + { + process->hold(); + } +} + +synchronization::IMemory::Type ControlBase::getMemoryType() const +{ + return CONTROL; +} + +bool ControlBase::isAvailable() +{ + return false; +} + +void ControlBase::alert() +{} + +bool ControlBase::remember(base::Sched* newObject) +{ + return false; +} + +bool ControlBase::forget(base::Sched* rememberedObject) +{ + return false; +} + +void ControlBase::eraseMemory() +{} + +} +} diff --git a/odemx-lite/src/coroutine/Coroutine.cpp b/odemx-lite/src/coroutine/Coroutine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65af561bfc2c294ea9055c7b726133f7f9ca1948 --- /dev/null +++ b/odemx-lite/src/coroutine/Coroutine.cpp @@ -0,0 +1,324 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Coroutine.cpp + * @author Ralf Gerstenberger + * @date created at 2002/01/22 + * @brief Implementation of odemx::coroutine::Coroutine + * @sa Coroutine.h + * @since 1.0 + */ + +#if defined(_MSC_VER) && defined(ODEMX_USE_SETJUMP) +#pragma warning(disable : 4530) +#endif + +#include <odemx/coroutine/Coroutine.h> + +#include <iostream> +#include <exception> +#include <memory.h> // memcpy +#include <stdexcept> + +namespace odemx { +namespace coroutine { + +//------------------------------------------------------construction/destruction + +Coroutine::Coroutine( CoroutineContext* c, CoroutineObserver* o ) +: data::Observable< CoroutineObserver >( o ) +, context( c ) +, parent( 0 ) +, caller( 0 ) +, state( CREATED ) +{ + // check for context existence: if 0, set default + if( ! context ) + { + context = getDefaultContext(); + } + // register coroutine with context + getContext()->beginCoroutine( this ); + + ODEMX_OBS(CoroutineObserver, Create(this)); + + myFiber = fiber = 0; +} + +Coroutine::~Coroutine() +{ + if( context->getActiveCoroutine() == this ) + { + std::cerr << "ODEMx ERROR: Coroutine::~Coroutine():" + << "destruction of active coroutine" + << std::endl; + } + + // clear Coroutine if necessary + if( getState() != TERMINATED ) + { + clear(); + } + + ODEMX_OBS(CoroutineObserver, Destroy(this)); + + freeStack (); +} + +//----------------------------------------------------------------------clean up + + +void Coroutine::freeStack() { + if( fiber != 0 ) + { + DeleteFiber( fiber ); + fiber = 0; + } +} + +void Coroutine::clear() +{ + if( state == TERMINATED ) + { + return; + } + ODEMX_OBS(CoroutineObserver, Clear(this)); + + setState( TERMINATED ); + + // leave context + getContext()->endCoroutine( this ); +} + +//----------------------------------------------------------------initialization + +void Coroutine::initialize() +{ + if( state != CREATED ) + { + throw std::runtime_error( "Coroutine::initialize(): internal error, " + "coroutine is already initialized" ); + } + +#ifdef _WIN32 + myFiber = fiber = CreateFiber( 0, (LPFIBER_START_ROUTINE)ExecFiber, this ); +#else + // TODO: fix this -> int cast with map index + myFiber = fiber = CreateFiber( 0, (void(*)(void*))ExecFiber, this ); +#endif + + if( fiber == 0 ) + { + throw std::runtime_error( "Coroutine::initialize(): failed to create " + "fiber, probably due to memory exhaustion" ); + } + + ODEMX_OBS(CoroutineObserver, Initialize(this)); + + setState( RUNNABLE ); +} + +//-----------------------------------------------------------------------getters + +CoroutineContext* Coroutine::getContext() +{ + return context; +} + +Coroutine* Coroutine::getParent() +{ + return parent; +} + +Coroutine* Coroutine::getCaller() +{ + return caller; +} + +//-------------------------------------------------switch to coroutine execution + +void Coroutine::switchTo() +{ + if( state == CREATED ) + { + // store return point + parent = context->getActiveCoroutine(); + initialize(); + } + caller = context->getActiveCoroutine(); + + if( caller != 0 ) + { + ODEMX_OBS(CoroutineObserver, SwitchTo(this, caller)) + } + else + { + ODEMX_OBS(CoroutineObserver, SwitchTo(this, context)); + } + + if( state != RUNNABLE ) + { + std::cerr << "ODEMx WARNING: Coroutine::switchTo(): switch to coroutine " + << "failed: Coroutine is not RUNNABLE, continue in parent" + << std::endl; + + if( parent != 0 ) + { + parent->switchTo(); + } + else + { + getContext()->switchTo(); + } + } + + if( context->getActiveCoroutine() == this ) + { + return; + } + + Coroutine* oldActive = context->setActiveCoroutine( this ); + + if( oldActive != 0 ) + { + // switchTo from Coroutine; + // Coroutine has to save 'switch in' point. + oldActive->saveFiber(); + } + else + { + // switchTo from context; + // CoroutineContext has to save 'switch out' point. + context->saveFiber(); + } + + FiberSwitch( fiber ); +} + +void Coroutine::operator()() +{ + switchTo(); +} + +void Coroutine::yield() +{ + if( parent != 0 ) + { + parent->switchTo(); + } + else + { + context->switchTo(); + } +} + + +//-----------------------------------------------------------------fiber storage + +void Coroutine::saveFiber() +{ + // get active fiber + fiber = GetCurrentFiber(); + + if( fiber == 0 ) + { + throw std::runtime_error( + "Coroutine::saveFiber(): could not retrieve active fiber" ); + } +} + +//---------------------------------------------------------------fiber execution + +VOID CALLBACK ExecFiber( PVOID param ) +{ + +#ifdef _WIN32 + Coroutine *p = static_cast<Coroutine*>( param ); +#else + void* theCoroutine = ucFiber::getCoroutine(param); + Coroutine* p = static_cast<Coroutine*>(theCoroutine); +#endif + + try + { + // start execution + p->run(); + } + catch( const std::exception& ) + { + throw; // rethrow anything that is derived from std::exception + } + catch(...) + { + // throw a real exception for whatever arrives here + throw std::runtime_error( + "ExecFiber(): non-exception object thrown in " + "coroutine: cannot say what()" ); + } + + // execution finished + p->clear(); + + // return + if( p->parent != 0 ) + { + p->parent->switchTo(); + } + else + { + p->context->switchTo(); + } + + // This point should never be reached. + throw std::runtime_error( + "ExecFiber(): internal error, return from coroutine failed" ); +} + +/** + \internal + \note FiberSwitch is a 'Work around'. + + In Visual C++ 6.0, when running a debug session, + SwitchToFiber() does not restore EIP-register (Instruction pointer). [Maybe correct] + FiberSwitch() ensures, that all calls to SwitchToFiber() + come from the same instruction point in code. +*/ +void FiberSwitch( LPVOID fiber ) +{ + SwitchToFiber( fiber ); +} + +//----------------------------------------------------------------state handling + +Coroutine::State Coroutine::setState( Coroutine::State newState ) +{ + Coroutine::State oldState = state; + state = newState; + + ODEMX_OBS_ATTR(CoroutineObserver, State, oldState, newState); + + return oldState; +} + +Coroutine::State Coroutine::getState() const +{ + return state; +} + +} } // namespace odemx::coroutine diff --git a/odemx-lite/src/coroutine/CoroutineContext.cpp b/odemx-lite/src/coroutine/CoroutineContext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f363feea1cb842cdcd652ccbaf3e6e1f8dd44a42 --- /dev/null +++ b/odemx-lite/src/coroutine/CoroutineContext.cpp @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file CoroutineContext.cpp + * @author Ralf Gerstenberger + * @date created at 2002/02/04 + * @brief Implementation of odemx::coroutine::CoroutineContext and DefaultContextutine + * @sa CoroutineContext.h + * @since 1.0 + */ + +#if defined(_MSC_VER) && defined(ODEMX_USE_SETJUMP) +#pragma warning(disable : 4530) +#endif + +#include <odemx/coroutine/CoroutineContext.h> +#include <odemx/coroutine/Coroutine.h> + +#include <memory.h> // memcpy +#include <stdexcept> + +namespace odemx { +namespace coroutine { + +//------------------------------------------------------construction/destruction + +CoroutineContext::CoroutineContext( CoroutineContextObserver* o ) +: data::Observable< CoroutineContextObserver >( o ) +, activeCoroutine( 0 ) +, numberOfCoroutines( 0 ) +{ + ODEMX_OBS(CoroutineContextObserver, Create(this)); + + fiber = 0; +} + +CoroutineContext::~CoroutineContext() +{ + ODEMX_OBS(CoroutineContextObserver, Destroy(this)); + + // check number of coroutines ?!? + // when the context is destroyed, the program should be finished anyway... + +} + +//-------------------------------------------------------------switch to context + +void CoroutineContext::switchTo() +{ + ODEMX_OBS(CoroutineContextObserver, SwitchTo(this, getActiveCoroutine())); + + if( getActiveCoroutine() == 0 ) + { + return; // ignore self-switch + } + + setActiveCoroutine( 0 ); + FiberSwitch( fiber ); +} + +//-----------------------------------------------------------------------getters + +Coroutine* CoroutineContext::getActiveCoroutine() +{ + return activeCoroutine; +} + +unsigned int CoroutineContext::getNumberOfCoroutines() +{ + return numberOfCoroutines; +} + +//--------------------------------------------------------------active coroutine + +Coroutine* CoroutineContext::setActiveCoroutine( Coroutine* c ) +{ + Coroutine* oldActiveCoroutine = activeCoroutine; + activeCoroutine = c; + + ODEMX_OBS_ATTR(CoroutineContextObserver, ActiveCoroutine, + oldActiveCoroutine, activeCoroutine); + + return oldActiveCoroutine; +} + +//---------------------------------------------------coroutine (de-)registration + +void CoroutineContext::beginCoroutine( Coroutine* cr ) +{ + assert( cr->getContext() == this ); + ++numberOfCoroutines; +} + +void CoroutineContext::endCoroutine( Coroutine* cr ) +{ + assert( cr->getContext() == this ); + --numberOfCoroutines; +} + +//-----------------------------------------------------------------fiber storage + +void CoroutineContext::saveFiber() +{ + // Initialize Fibers + if( initFibers ) + { + ConvertThreadToFiber( 0 ); + initFibers = false; + } + + // get context + fiber = GetCurrentFiber(); + + if( fiber == 0 ) + { + throw std::runtime_error( + "CoroutineContext::saveFiber(): could not retrieve active fiber" ); + } +} + +bool CoroutineContext::initFibers = true; + +//---------------------------------------------------------------default context + +/** \brief Get a default coroutine context + \return pointer to the DefaultContext + \relates DefaultContext +*/ +CoroutineContext* getDefaultContext() +{ + static DefaultContext defaultContext; + return &defaultContext; +} + +DefaultContext::DefaultContext() +: CoroutineContext() +{ +} + +} } // namespace odemx::base diff --git a/odemx-lite/src/coroutine/ucFiber.cpp b/odemx-lite/src/coroutine/ucFiber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a2ec924e3dd4ea2f42cc586676f0d561a5dc099 --- /dev/null +++ b/odemx-lite/src/coroutine/ucFiber.cpp @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ucFiber.cpp + * @author Klaus Ahrens + * @date created at 2009/03/16 + * @brief Implementation of class ucFiber + * @sa ucFiber.h + * @since 3.0 + */ + +#ifndef _WIN32 + +#include <odemx/coroutine/ucFiber.h> +#include <cstdio> +#include <cassert> + +namespace odemx { +namespace coroutine { + +std::map<int, void*> ucFiber::allFibers; +int ucFiber::nFibers = 0; + +ucFiber::ucFiber(void* param): + uc_(new ucontext_t), + callStack_(0), + stackState_(mainStack) +{ + getcontext(uc_); +} + +ucFiber::ucFiber(std::size_t stacksize, void (*start)(void*), void* param): + uc_(new ucontext_t), + callStack_(0), + stackState_(noStack) +{ + getcontext(uc_); + + uc_->uc_stack.ss_flags = 0; + if (!stacksize) stacksize = ODEMX_DEFAULT_STACK_SIZE; + uc_->uc_stack.ss_size = stacksize; + callStack_ = std::malloc(stacksize); + uc_->uc_stack.ss_sp = callStack_; + + if (uc_->uc_stack.ss_sp) { + stackState_ = okStack; + tos = uc_->uc_stack.ss_sp; + allFibers[nFibers]=param; + makecontext(uc_, (void(*)())start, 1, nFibers++); + } +} + +void* ucFiber::getCoroutine(int nr) { + return allFibers[nr]; +} + +ucFiber::~ucFiber() +{ + // assert(uc_->uc_stack.ss_sp == callStack_); + // fails because ss_sp is the stack pointer + // points to the current position of the call stack + + // if (stackState_== okStack) std::free(uc_->uc_stack.ss_sp); + + //delete the original stack + if (stackState_== okStack) std::free(callStack_); + + delete uc_; +} + +ucFiber* ucFiber::current = 0; + +void* ucFiber::ConvertThreadToFiber(void* param) { + return current = new ucFiber(param); +} + +void* ucFiber::GetCurrentFiber() { + return current; +} + +void* ucFiber::CreateFiber(std::size_t stacksize, void (*start)(void*), void* param) { + ucFiber* fiber = new ucFiber(stacksize, start, param); + if (fiber->stackState_ == noStack) + { delete fiber; return 0; } // error, must be handled by caller (Coroutine) + else + return fiber; +} + +void ucFiber::DeleteFiber(void* fiber) { + delete reinterpret_cast<ucFiber*>(fiber); +} + +void ucFiber::SwitchToFiber(void* fiber) { + ucFiber* from = current; + ucFiber* to = reinterpret_cast<ucFiber*>(fiber); + + current = to; + + swapcontext(from->uc_, to->uc_); +} + +void ucFiber::stackcheck() { + int probe; + char* stackAt = (char*) &probe; + ucFiber* f = reinterpret_cast<ucFiber*>(current); + + if ((stackAt - (char*)f->tos) <1024) throw "Fiber: Stack Overflow ahead ..."; +} + +} } // namespace odemx::coroutine + +#endif /* _WIN32 */ diff --git a/odemx-lite/src/data/LoggingManager.cpp b/odemx-lite/src/data/LoggingManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56777a587c68ba060d88a51aa3d58d28d0b26ee5 --- /dev/null +++ b/odemx-lite/src/data/LoggingManager.cpp @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file LoggingManager.cpp + * @author Ronald Kluth + * @date created at 2009/03/18 + * @brief Implementation of odemx::data::LoggingManager + * @sa LoggingManager.h + * @since 3.0 + */ + +#include <odemx/data/LoggingManager.h> +#include <odemx/base/Simulation.h> +#include <odemx/data/Producer.h> +#include <odemx/data/buffer/StatisticsBuffer.h> +//#include <odemx/data/output/DatabaseWriter.h> +#include <odemx/data/output/ErrorWriter.h> +#include <odemx/data/output/OStreamWriter.h> +//#include <odemx/data/output/XmlWriter.h> +#include <odemx/data/output/OStreamReport.h> +//#include <odemx/data/output/XmlReport.h> +#include <odemx/util/Exceptions.h> + +#include <iostream> // std::cout for default logging + +namespace odemx { +namespace data { + +//------------------------------------------------------------------local struct + +typedef std::shared_ptr< Log::Consumer<SimRecord> > ConsumerPtr; + +struct DefaultLogConfig +{ + ConsumerPtr writer; + std::shared_ptr< data::buffer::StatisticsBuffer > statsBuffer; +}; + +//------------------------------------------------------construction/destruction + +LoggingManager::LoggingManager() +: Log::ChannelManager< SimRecord >() +, defaultLogConfig_( nullptr ) +{ + initErrorLogging(); +} + +LoggingManager::LoggingManager( const std::string& defLabel, + const char defSpace ) +: Log::ChannelManager< SimRecord >( defLabel, defSpace ) +, defaultLogConfig_( nullptr ) +{ + initErrorLogging(); +} + +LoggingManager::~LoggingManager() +{ +} + +//---------------------------------------------------------------default logging + +void LoggingManager::initErrorLogging() +{ + using namespace std; + using namespace output; + + // we don't keep a pointer to the error writer as member + // because it is not intended to be accessed by anyone + shared_ptr< ErrorWriter > cerrWriter = ErrorWriter::create(); + getChannel( channel_id::warning )->addConsumer( cerrWriter ); + getChannel( channel_id::error )->addConsumer( cerrWriter ); + getChannel( channel_id::fatal )->addConsumer( cerrWriter ); +} + +bool LoggingManager::enableDefaultLogging( output::Type type, + const std::string& location ) +{ + using namespace buffer; + using namespace output; + + // only initialize once + if( ! defaultLogConfig_.get() ) + { + // make sure the channels are initialized + // error channels are active due to default error logging + getChannel( channel_id::trace ); + getChannel( channel_id::debug ); + getChannel( channel_id::info ); + getChannel( channel_id::statistics ); + + // create log config to keep a pointer to the statistics buffer + std::unique_ptr< DefaultLogConfig > tmpLogConfig( new DefaultLogConfig ); + + switch( type ) + { + case DATABASE: +// if( location.empty() ) +// { +// throw DataOutputException( "LogginManager::enableDefaultLogging():" +// "database connection string empty" ); +// } +// tmpLogConfig->writer = DatabaseWriter::create( location ); + break; + case STDOUT: + tmpLogConfig->writer = OStreamWriter::create( std::cout ); + break; + case XML: +// if( location.empty() ) +// { +// throw DataOutputException( "LoggingManager::enableDefaultLogging():" +// "XML base file name empty" ); +// } +// tmpLogConfig->writer = XmlWriter::create( location, 1000 ); + break; + default: + break; + } + + defaultLogConfig_ = std::move(tmpLogConfig); + + // add the default output writer to all log channels + addConsumer( defaultLogConfig_->writer ); + + // create the default statistics buffer and add it as consumer + defaultLogConfig_->statsBuffer = + StatisticsBuffer::create( + dynamic_cast< base::Simulation& >( *this ), + "Default Statistics Buffer" ); + addConsumer( channel_id::statistics, defaultLogConfig_->statsBuffer ); + + return true; + } + return false; +} + +bool LoggingManager::disableDefaultLogging() +{ + using namespace buffer; + using namespace output; + + if( defaultLogConfig_.get() ) + { + removeConsumer( defaultLogConfig_->writer ); + removeConsumer( data::channel_id::statistics, defaultLogConfig_->statsBuffer ); + defaultLogConfig_.reset( 0 ); + return true; + } + return false; +} + +bool LoggingManager::resetDefaultStatistics( base::SimTime currentTime ) +{ + // check if default logging has been enabled + if( ! defaultLogConfig_.get() ) + { + return false; + } + // reset the statistics buffer + defaultLogConfig_->statsBuffer->reset( currentTime ); + return true; +} + +bool LoggingManager::reportDefaultStatistics( output::Type type, + const std::string& location ) +{ + using namespace data::output; + + // check if default logging has been enabled + if( ! defaultLogConfig_.get() ) + { + return false; + } + + std::unique_ptr< Report > report; + switch( type ) + { + case STDOUT: + report.reset( new OStreamReport( std::cout ) ); + break; + case XML: +// if( location.empty() ) +// { +// throw DataOutputException( "LoggingManager::reportDefaultStatistics(): " +// "XML file name empty" ); +// } +// report.reset( new XmlReport( location ) ); + break; + case DATABASE: +// throw DataOutputException( "LoggingManager::reportDefaultStatistics(): " +// "database output not supported" ); + break; + } + + // generate report from the default statistics buffer + report->addReportProducer( *defaultLogConfig_->statsBuffer ); + report->generateReport(); + return true; +} + +} } // namespace odemx::data diff --git a/odemx-lite/src/data/ManagedChannels.cpp b/odemx-lite/src/data/ManagedChannels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3cbcea46ae2d66bf24a97622bf56f74d074c0dc7 --- /dev/null +++ b/odemx-lite/src/data/ManagedChannels.cpp @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ManagedChannels.cpp + * @author Ronald Kluth + * @date created at 2009/09/05 + * @brief Implementation of function odemx::data::channel_id::toString + * @sa ManagedChannels.h + * @since 3.0 + */ + +#include <odemx/data/ManagedChannels.h> + +namespace odemx { +namespace data { +namespace channel_id { + +const std::string toString( const Log::ChannelId id ) +{ + using namespace Log::Detail; + + switch( id ) + { + case trace: return "trace"; + case debug: return "debug"; + case info: return "info"; + case warning: return "warning"; + case error: return "error"; + case fatal: return "fatal"; + case statistics: return "statistics"; + default: return "user-defined"; + } +} + +} } } // namesapce odemx::data::channel_id diff --git a/odemx-lite/src/data/Producer.cpp b/odemx-lite/src/data/Producer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78c413fc007a5f5771a1937b412e239d84cc1717 --- /dev/null +++ b/odemx-lite/src/data/Producer.cpp @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Producer.cpp + * @author Ronald Kluth + * @date created at 2009/03/18 + * @brief Implementation of class odemx::data::Producer + * @sa Producer.h + * @since 3.0 + */ + +#include <odemx/data/Producer.h> +#include <odemx/base/DefaultSimulation.h> +#include <odemx/base/Simulation.h> + +namespace odemx { +namespace data { + +//------------------------------------------------------construction/destruction + +Producer::Producer( base::Simulation& sim, const Label& label ) +: ProducerBase( sim, label ) +, sim_( &sim ) +{ +} + +Producer::~Producer() +{ +} + +//----------------------------------------------------------------enable/disable + +void Producer::enableLogging() +{ + trace = sim_->getChannel( channel_id::trace ); + debug = sim_->getChannel( channel_id::debug ); + info = sim_->getChannel( channel_id::info ); + statistics = sim_->getChannel( channel_id::statistics ); +} + +void Producer::disableLogging() +{ + trace.reset(); + debug.reset(); + info.reset(); + statistics.reset(); +} + +//------------------------------------------------------------object information + +const Label& Producer::getLabel() const +{ + return getName(); +} + +const TypeInfo Producer::getType() const +{ + return typeid( *this ); +} + +//---------------------------------------------------------------record creation + +SimRecord Producer::log( const StringLiteral& text ) const +{ + return SimRecord( *sim_, *this, text ); +} + +//-----------------------------------------------------------convenience methods + +SimRecord Producer::reset() const +{ + return log( "reset" ); +} + +SimRecord Producer::count( const StringLiteral& name, std::size_t value ) const +{ + return log( "count" ).detail( name, value ); +} + +//-------------------------------------------------------------simulation access + +const base::Simulation& Producer::getSimulation() const +{ + return *sim_; +} + +base::Simulation& Producer::getSimulation() +{ + return *sim_; +} + +//---------------------------------------------------------------------streaming + +std::ostream& operator<<( std::ostream& os, const data::Producer& obj ) +{ + os << obj.getLabel(); + return os; +} + +std::ostream& operator<<( std::ostream& os, const data::Producer* ptr ) +{ + assert( ptr ); + + os << ptr->getLabel(); + return os; +} + +} } // namespace odemx::data diff --git a/odemx-lite/src/data/Report.cpp b/odemx-lite/src/data/Report.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d5dbd93f6e2a88b7ecbecedd936035c5a36d600 --- /dev/null +++ b/odemx-lite/src/data/Report.cpp @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002 - 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Report.cpp + * @author Ralf Gerstenberger + * @date created at 2002/06/21 + * @brief Implementation of class odemx::data::Report + * @sa Report.h + * @since 1.0 + */ + +#include <odemx/data/Report.h> +#include <odemx/data/ReportProducer.h> +#include <odemx/util/DeletePtr.h> + +#include <cassert> +#include <algorithm> + +namespace odemx { +namespace data { + +Report::~Report() +{ + std::for_each( tables_.begin(), tables_.end(), DeletePtr< ReportTable >() ); +} + +void Report::addReportProducer( ReportProducer& reporter ) +{ + producers_.insert( &reporter ); +} + +void Report::removeReportProducer( ReportProducer& reporter ) +{ + producers_.erase( &reporter ); +} + +ReportTable& Report::getTable( const std::string& name, const ReportTable::Definition& def ) +{ + ReportTable* tmp = findTable( name, def ); + + if( ! tmp ) + { + tmp = new ReportTable( name, def ); + tables_.push_back( tmp ); + } + return *tmp; +} + +ReportTable* Report::findTable( const std::string& name, const ReportTable::Definition& def ) const +{ + assert( ! name.empty() ); + + for( TableVec::const_iterator iter = tables_.begin(); + iter != tables_.end(); ++iter ) + { + ReportTable* current = *iter; + + // compare table def and name to find a matching table + if( current->getDefinition() == def + && current->getLabel() == name ) + { + return current; + } + } + return 0; +} + + + +void Report::generateReport() +{ + if( producers_.empty() ) + { + return; + } + + startProcessing(); + + // call all report producers to create and fill their tables + for( ReportProducerSet::iterator iter = producers_.begin(); + iter != producers_.end(); ++iter ) + { + ( *iter )->report( *this ); + } + + processTables(); + + endProcessing(); +} + +} } // namespace odemx::data diff --git a/odemx-lite/src/data/ReportProducer.cpp b/odemx-lite/src/data/ReportProducer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa26bce477fa760f31b54d12095687588293508f --- /dev/null +++ b/odemx-lite/src/data/ReportProducer.cpp @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002 - 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ReportProducer.cpp + * @author Ralf Gerstenberger + * @date created at 2002/06/21 + * @brief Implementation of class odemx::data::ReportProducer + * @sa ReportProducer.h + * @since 1.0 + */ + +#include <odemx/data/ReportProducer.h> +#include <odemx/base/Simulation.h> + +namespace odemx { +namespace data { + +ReportProducer::ReportProducer( base::Simulation& sim, const Label& label ) +: Log::NamedElement( sim, label ) +{ +} + +ReportProducer::~ReportProducer() +{ +} + +const Label& ReportProducer::getLabel() const +{ + return getName(); +} + +} } // namespace odemx::data diff --git a/odemx-lite/src/data/ReportTable.cpp b/odemx-lite/src/data/ReportTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd4d72d906456825078ae4dca30ad17f803848dc --- /dev/null +++ b/odemx-lite/src/data/ReportTable.cpp @@ -0,0 +1,710 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ReportTable.cpp + * @author Ronald Kluth + * @date created at 2009/12/17 + * @brief Implementation of class odemx::data::ReportTable + * @sa ReportTable.h + * @since 3.0 + */ + +#include <odemx/data/ReportTable.h> +#include <odemx/base/SimTime.h> +#include <odemx/util/Exceptions.h> +#include <odemx/setup.h> + +#include <stdexcept> +#include <sstream> + +namespace odemx { +namespace data { + +/********************** Column *********************************************/ + +const std::string ReportTable::Column::typeToString( ReportTable::Column::Type t ) +{ + switch( t ) + { + case Column::BAR: return std::string( "BAR" ); + case Column::SIMTIME: return std::string( "SIMTIME" ); + case Column::INTEGER: return std::string( "INTEGER" ); + case Column::REAL: return std::string( "REAL" ); + case Column::STRING: return std::string( "STRING" ); + default: return std::string( "UNKNOWN COLUMN TYPE" ); + } +} + +/********************* Table Definition ***********************************/ + +// compare table definitions, used to determine if two tables are the same +bool operator==( const ReportTable::Definition& lhs, const ReportTable::Definition& rhs ) +{ + ReportTable::SizeType columns = lhs.getNumberOfColumns(); + + // check for same column number + if( columns != rhs.getNumberOfColumns() ) + { + return false; + } + + // compare each column by type and label + for( ReportTable::SizeType i = 0; i < columns; ++i ) + { + if( lhs.getTypeOfColumn( i ) != rhs.getTypeOfColumn( i ) + || lhs.getLabelOfColumn( i ) != rhs.getLabelOfColumn( i ) ) + { + return false; + } + } + // all checks passed + return true; +} + +ReportTable::SizeType ReportTable::Definition::getNumberOfColumns() const +{ + return columnLabels_.size(); +} + +const std::string& ReportTable::Definition::getLabelOfColumn( ReportTable::SizeType index ) const +{ + static const std::string error( "ERROR" ); + return ( index < columnLabels_.size() ) ? + columnLabels_[ index ] : error; +} + +ReportTable::Column::Type ReportTable::Definition::getTypeOfColumn( ReportTable::SizeType index ) const +{ + return ( index < columnTypes_.size() ) ? + columnTypes_[ index ] : ReportTable::Column::INVALID; +} + +void ReportTable::Definition::addColumn( const std::string& label, ReportTable::Column::Type type ) +{ + if( label.empty() || type == Column::INVALID ) + { + return; + } + columnLabels_.push_back( label ); + columnTypes_.push_back( type ); +} + +/********************* Table Functions ***********************************/ + +/// Construction is managed by Report +ReportTable::ReportTable( const Label& label, const ReportTable::Definition& def ) +: label_( label ) +, def_( def ) +, lineCount_( 0 ) +{ + // create vectors for columns according to TableDefinition + for( ReportTable::SizeType i = 0; i < def.getNumberOfColumns(); ++i ) + { + Column* newColumn = 0; + + // create each column according to the given type + switch( def.getTypeOfColumn(i) ) + { + case Column::BAR: + newColumn = new ColumnT< long >( def.getLabelOfColumn( i ), Column::BAR ); + break; + case Column::INTEGER: + newColumn = new ColumnT< long >( def.getLabelOfColumn( i ), Column::INTEGER ); + break; + case Column::REAL: + newColumn = new ColumnT< double >( def.getLabelOfColumn( i ), Column::REAL ); + break; + case Column::STRING: + newColumn = new ColumnT< std::string >( def.getLabelOfColumn( i ), Column::STRING ); + break; + case Column::SIMTIME: + newColumn = new ColumnT< base::SimTime >( def.getLabelOfColumn( i ), Column::SIMTIME ); + break; + default: // INVALID + throw std::logic_error( "ReportTable::ReportTable(): invalid column type" ); + break; + } + + if( ! newColumn ) + { + throw DataException( "ReportTable::ReportTable(): invalid column type" ); + } + columns_.push_back( newColumn ); + } +} + +ReportTable::~ReportTable() +{ + // clean up columns + for( ColumnVec::const_iterator iter = columns_.begin(); + iter != columns_.end(); ++iter ) + { + delete *iter; + } +} + +/********************** Input Streaming **********************************/ + +// only four functions actually add data, the others are merely +// wrappers using the three operator << implementations + +// this function deals with INTEGER and with BAR column types +ReportTable& operator<<( ReportTable& t, long d ) +{ + // try to get the current column according to inputPosition + // this also checks for the correct type of column + ReportTable::ColumnT< long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long >* >( t.getCurrentInputColumn() ); + + // test column type + if ( currentColumn ) + { + currentColumn->addData( d ); + } + else + { + throw DataException( "ReportTable operator<<(long): wrong column " + "type at input position; cannot enter data into Table" ); + } + + // set input pointer to next position for streaming + t.advanceInputPosition(); + return t; +} + + +ReportTable& operator<<( ReportTable& t, long long d ) +{ + return t << (long)d; +#if 0 + // try to get the current column according to inputPosition + // this also checks for the correct type of column + ReportTable::ColumnT< long long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long long >* >( t.getCurrentInputColumn() ); + + // test column type + if( currentColumn ) + { + currentColumn->addData( d ); + } + else + { + throw DataException( "ReportTable operator<<(long long): " + "wrong column type at input position; cannot enter data into Table" ); + } + + // set input pointer to next position for streaming + t.advanceInputPosition(); + return t; +#endif +} + + +// the above function forces use of this one: +ReportTable& operator<<( ReportTable& t, double d ) +{ + // try to get the current column according to inputPosition + // this also checks for the correct type of column, returns 0 if wrong + ReportTable::ColumnT< double >* currentColumn = + dynamic_cast< ReportTable::ColumnT< double >* >( t.getCurrentInputColumn() ); + + // test column type + if( currentColumn ) + { + currentColumn->addData( d ); + } + else + { + throw DataException( "ReportTable operator<<(double): wrong " + "column type at input position; cannot enter data into Table" ); + } + + // set input pointer to next position for streaming + t.advanceInputPosition(); + return t; +} + +ReportTable& operator<<( ReportTable& t, const std::string& s ) +{ + // try to get the current column according to inputPosition + // this also checks for the correct type of column, returns 0 if wrong + ReportTable::ColumnT< std::string >* currentColumn = + dynamic_cast< ReportTable::ColumnT< std::string >* >( t.getCurrentInputColumn() ); + + // test column type + if( currentColumn ) + { + currentColumn->addData( s ); + } + else + { + throw DataException( "ReportTable operator<<(string): wrong " + "column type at input position; cannot enter data into Table" ); + return t; + } + + // set input pointer to next position for streaming + t.advanceInputPosition(); + return t; +} + +ReportTable& operator<<( ReportTable& t, int i ) +{ + return t << (long)i; +} + +ReportTable& operator<<( ReportTable& t, unsigned int i ) +{ + return t << (long)i; +} + +ReportTable& operator<<( ReportTable& t, unsigned long i ) +{ + return t << (long)i; +} + +ReportTable& operator<<( ReportTable& t, unsigned long long i ) +{ + return t << (long long)i; +} + +ReportTable& operator<<( ReportTable& t, float f ) +{ + return t << (double)f; +} + +ReportTable& operator<<( ReportTable& t, const char* s ) +{ + return t << std::string( s ); +} + + +// this function is used to skip table cells or the rest of the line +ReportTable& operator<<( ReportTable& t, ReportTable::Definition::ControlCode cc ) +{ + ReportTable::SizeType line; + + // control codes may end a line early + // or cause a jump to the next table cell + switch( cc ) + { + case ReportTable::Definition::ENDL: + // fill line with default values + line = t.lineCount_; + + while( line == t.lineCount_ ) + { + // enter default value + t.addDefaultValue(); + } + break; + case ReportTable::Definition::TAB: + // enter default value + t.addDefaultValue(); + break; + default: + throw DataException( "ReportTable operator<<(ControlCode): unknown " + "control code; cannot enter data into table" ); + } + return t; +} + +void ReportTable::addDefaultValue() +{ + Column* currentCol = getCurrentInputColumn(); + + // enter default value + switch( currentCol->getType() ) + { + case Column::SIMTIME: + dynamic_cast< ColumnT< base::SimTime >* >( currentCol )->addData( 0 ); + break; + case Column::BAR: // fall through + case Column::INTEGER: + dynamic_cast< ColumnT< long >* >( currentCol )->addData( 0 ); + break; + case Column::REAL: + dynamic_cast< ColumnT< double >* >( currentCol )->addData( 0.0 ); + break; + case Column::STRING: + dynamic_cast< ColumnT< std::string >* >( currentCol )->addData( "" ); + break; + default: + throw DataException( "ReportTable::addDefaultValue(): invalid " + "column type, cannot add data" ); + } + + // update inputColumnPointer + advanceInputPosition(); +} + +/******************** Output streaming ************************************/ + +ReportTable& operator>>( ReportTable& t, long long& to ) +{ + // try to get the current column according to outputPosition + // this also checks for the correct type of column + ReportTable::ColumnT< long long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long long >* >( t.getCurrentOutputColumn() ); + + // test column type + if( currentColumn ) + { + to = currentColumn->getData( t.getOutputLine() ); + } + else + { + throw DataException( "ReportTable::operator>>(long long): " + "wrong column type, cannot extract data" ); + } + + // set output pointer to next position for streaming + t.advanceOutputPosition(); + return t; +} + +ReportTable& operator>>( ReportTable& t, unsigned long long& to ) +{ + // try to get the current column according to outputPosition + // this also checks for the correct type of column, returns 0 if wrong + if( ReportTable::ColumnT< unsigned long long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< unsigned long long >* >( + t.getCurrentOutputColumn() ) ) + { + to = currentColumn->getData( t.getOutputLine() ); + } + else if( ReportTable::ColumnT< long long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long long >* >( + t.getCurrentOutputColumn() ) ) + { + to = currentColumn->getData( t.getOutputLine() ); + } + else + { + throw DataException( "ReportTable::operator>>(unsigned long long):" + "wrong column type, cannot extract data" ); + } + + // set output pointer to next position for streaming + t.advanceOutputPosition(); + return t; +} + +ReportTable& operator>>( ReportTable& t, long& to ) +{ + // try to get the current column according to outputPosition + // this also checks for the correct type of column, returns 0 if wrong + ReportTable::ColumnT< long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long >* >( t.getCurrentOutputColumn() ); + + // test column type + if ( currentColumn ) + { + to = currentColumn->getData( t.getOutputLine() ); + } + else + { + throw DataException( "ReportTable::operator>>(long):" + "wrong column type, cannot extract data" ); + } + + // set output pointer to next position for streaming + t.advanceOutputPosition(); + return t; +} + +ReportTable& operator>>( ReportTable& t, double& to ) +{ + // try to get the current column according to outputPosition + // this also checks for the correct type of column, is 0 if wrong + ReportTable::ColumnT< double >* currentColumn = + dynamic_cast< ReportTable::ColumnT< double >* >( t.getCurrentOutputColumn() ); + + // test column type + if( currentColumn ) + { + to = currentColumn->getData( t.getOutputLine() ); + } + else + { + ReportTable::ColumnT< long >* currentColumn = + dynamic_cast< ReportTable::ColumnT<long>* >( t.getCurrentOutputColumn() ); + + if( currentColumn ) + { + to = (double)currentColumn->getData( t.getOutputLine() ); + } + else + { + throw DataException( "ReportTable::operator>>(double): " + "wrong column type, cannot extract data" ); + } + } + + // set output pointer to next position for streaming + t.advanceOutputPosition(); + return t; +} + +ReportTable& operator>>( ReportTable& t, std::string& to ) +{ + // any column type accepted, conversion with ostringstream + std::ostringstream convert; + + ReportTable::Column* currentColumn = t.getCurrentOutputColumn(); + + // try to get the current column according to outputPosition + // this also checks for the correct type of column + switch( currentColumn->getType() ) + { + case ReportTable::Column::BAR: // fall through + case ReportTable::Column::INTEGER: + convert << dynamic_cast< ReportTable::ColumnT< long >* > + ( currentColumn )->getData( t.getOutputLine() ); + break; + case ReportTable::Column::REAL: + convert << dynamic_cast< ReportTable::ColumnT< double >* > + ( currentColumn )->getData( t.getOutputLine() ); + break; + case ReportTable::Column::STRING: + convert << dynamic_cast< ReportTable::ColumnT< std::string >* > + ( currentColumn )->getData( t.getOutputLine() ); + break; + case ReportTable::Column::SIMTIME: + convert << dynamic_cast< ReportTable::ColumnT< base::SimTime >* > + ( currentColumn )->getData( t.getOutputLine() ); + break; + default: + DataException( "ReportTable::operator>>(string): " + "invalid column type, cannot extract data" ); + } + + // write string to stream + to = convert.str(); + + // update outputColumnPointer + t.advanceOutputPosition(); + return t; +} + + +/****************** Random Access Output **********************************/ + +base::SimTime ReportTable::getSIMTIME( ReportTable::SizeType col, ReportTable::SizeType line ) +{ + if( col >= columns_.size() ) + { + throw std::out_of_range( "ReportTable::getSIMTIME(): column out of range" ); + } + if( line >= lineCount_ ) + { + throw std::out_of_range( "ReportTable::getSIMTIME(): line out of range" ); + } + + // try to get the column col, check for the correct type, is 0 if wrong + ReportTable::ColumnT< base::SimTime >* currentColumn = + dynamic_cast< ReportTable::ColumnT< base::SimTime >* >( columns_[ col ] ); + + // test column type + if( currentColumn + && currentColumn->getType() == ReportTable::Column::SIMTIME ) + { + return (base::SimTime) currentColumn->getData( line ); + } + else + { + throw DataException( "ReportTable::getSIMTIME(): wrong column type; " + "cannot extract data" ); + } +} + + +long ReportTable::getBAR( ReportTable::SizeType col, ReportTable::SizeType line ) +{ + if( col >= columns_.size() ) + { + throw std::out_of_range( "ReportTable::getBAR(): column out of range" ); + } + if( line >= lineCount_ ) + { + throw std::out_of_range( "ReportTable::getBAR(): line out of range" ); + } + + // try to get the column col, check for the correct type, is 0 if wrong + ReportTable::ColumnT< long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long >* >( columns_[ col ] ); + + // test column type + if( currentColumn + && currentColumn->getType() == Column::BAR ) + { + return currentColumn->getData( line ); + } + else + { + throw DataException( "ReportTable::getBAR(): wrong column type; " + "cannot extract data" ); + } +} + +long ReportTable::getINTEGER( ReportTable::SizeType col, ReportTable::SizeType line ) +{ + if( col >= columns_.size() ) + { + throw std::out_of_range( "ReportTable::getINTEGER(): column out of range" ); + } + if( line >= lineCount_ ) + { + throw std::out_of_range( "ReportTable::getINTEGER(): line out of range" ); + } + + // try to get the column col, check for the correct type, is 0 if wrong + ReportTable::ColumnT< long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long >* >( columns_[ col ] ); + + // test column type + if ( currentColumn + && currentColumn->getType() == Column::INTEGER ) + { + return currentColumn->getData( line ); + } + else + { + throw DataException( "ReportTable::getINTEGER(): wrong column type; " + "cannot extract data" ); + } +} + +double ReportTable::getREAL( ReportTable::SizeType col, ReportTable::SizeType line ) +{ + if( col >= columns_.size() ) + { + throw std::out_of_range( "ReportTable::getREAL(): column out of range" ); + } + if( line >= lineCount_ ) + { + throw std::out_of_range( "ReportTable::getREAL(): line out of range" ); + } + + // try to get the column col, check for the correct type, is 0 if wrong + ReportTable::ColumnT< double >* currentColumn = + dynamic_cast< ReportTable::ColumnT< double >* >( columns_[ col ] ); + + // test column type + if( currentColumn + && currentColumn->getType() == Column::REAL ) + { + return currentColumn->getData( line ); + } + else + { + // cast from long type is also allowed + ReportTable::ColumnT< long >* currentColumn = + dynamic_cast< ReportTable::ColumnT< long >* >( columns_[ col ] ); + + if( currentColumn + && currentColumn->getType() == Column::INTEGER ) + { + return (double)currentColumn->getData( line ); + } + else + { + throw DataException( "ReportTable::getREAL(): wrong column type; " + "cannot extract data" ); + } + } +} + +std::string ReportTable::getSTRING( ReportTable::SizeType col, ReportTable::SizeType line ) +{ + if( col >= columns_.size() ) + { + throw std::out_of_range( "ReportTable::getSTRING(): column out of range" ); + } + if( line >= lineCount_ ) + { + throw std::out_of_range( "ReportTable::getSTRING(): line out of range" ); + } + + // any column type accepted, conversion with std::ostringstream + std::ostringstream convert; + ReportTable::Column* currentColumn = columns_[ col ]; + + // checks for the correct type of column, returns 0 if wrong + switch( currentColumn->getType() ) + { + case ReportTable::Column::BAR: // fall through + case ReportTable::Column::INTEGER: + convert << dynamic_cast< ReportTable::ColumnT< long >* > + ( currentColumn )->getData( line ); + break; + case ReportTable::Column::SIMTIME: + convert << dynamic_cast< ReportTable::ColumnT< base::SimTime >* > + ( currentColumn )->getData( line ); + break; + case ReportTable::Column::REAL: + convert << dynamic_cast< ReportTable::ColumnT< double >* > + ( currentColumn )->getData( line ); + break; + case ReportTable::Column::STRING: + convert << dynamic_cast< ReportTable::ColumnT< std::string >* > + ( currentColumn )->getData( line ); + break; + default: + throw DataException( "ReportTable::getSTRING(): unknown column type; " + "cannot extract data" ); + } + return convert.str(); +} + +// help procedures +void ReportTable::advanceInputPosition() +{ + // advance the inputPosition by one + ++inputPosition_.col; + + // check for line end + if( inputPosition_.col >= getNumberOfColumns() ) + { + inputPosition_.col = inputPosition_.col % getNumberOfColumns(); + ++inputPosition_.line; + ++lineCount_; + } +} + +void ReportTable::advanceOutputPosition() +{ + // advance the outputPosition by one + ++outputPosition_.col; + + // check for line end + if( outputPosition_.col >= getNumberOfColumns() ) + { + outputPosition_.col = outputPosition_.col % getNumberOfColumns(); + ++outputPosition_.line; + } + + // wrap output streaming at last line to start anew + if( outputPosition_.line >= getNumberOfLines() ) + { + outputPosition_.line = 0; + } +} + +} } // namespace data diff --git a/odemx-lite/src/data/SimRecord.cpp b/odemx-lite/src/data/SimRecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3154915a12902ee2580d4ae0f9b23ef5c7824acc --- /dev/null +++ b/odemx-lite/src/data/SimRecord.cpp @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimRecord.cpp + * @author Ronald Kluth + * @date created at 2009/03/16 + * @brief Implementation of class odemx::data::SimRecord + * @sa SimRecord.h + * @since 3.0 + */ + +#include <odemx/data/SimRecord.h> +#include <odemx/base/Simulation.h> +#include <odemx/util/Exceptions.h> + +namespace odemx { +namespace data { + +//------------------------------------------------------construction/destruction + +SimRecord::SimRecord( const base::Simulation& sim, const Producer& sender, + const StringLiteral& text ) +: text_( text ) +, sim_( &sim ) +, sender_( &sender ) +, time_( sim.getTime() ) +, scope_() +, details_() +{ +} + +SimRecord::~SimRecord() +{ +} + +//-------------------------------------------------------------------data checks + +bool SimRecord::hasScope() const +{ + return scope_.isSet(); +} + +bool SimRecord::hasDetails() const +{ + return !! details_; +} + +//------------------------------------------------------------class scope setter + +SimRecord& SimRecord::scope( const TypeInfo& type ) +{ + scope_ = type; + return *this; +} + +//------------------------------------------------------------------data getters + +const StringLiteral& SimRecord::getText() const +{ + return text_; +} + +const base::Simulation& SimRecord::getSimulation() const +{ + return *sim_; +} + +const Producer& SimRecord::getSender() const +{ + return *sender_; +} + +base::SimTime SimRecord::getTime() const +{ + return time_; +} + +const TypeInfo& SimRecord::getScope() const +{ + return scope_; +} + +const SimRecord::DetailVec& SimRecord::getDetails() const +{ + if( ! details_ ) + { + throw DataException( "SimRecord::getDetails(): " + "detail vector pointer not initialized, check hasDetails()" ); + } + return *details_; +} + +const std::shared_ptr< SimRecord::DetailVec > SimRecord::getDetailPointer() const +{ + return details_; +} + +void SimRecord::initDetailVec() +{ + details_.reset( new DetailVec() ); +} + +} } // namespace odemx::data diff --git a/odemx-lite/src/data/SimRecordFilter.cpp b/odemx-lite/src/data/SimRecordFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e4d887393e61e39f3b50fdab08e8b3f79d9878c --- /dev/null +++ b/odemx-lite/src/data/SimRecordFilter.cpp @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimRecordFilter.cpp + * @author Ronald Kluth + * @date created at 2009/03/18 + * @brief Implementation of class odemx::data::SimRecordFilter + * @sa SimRecordFilter.h + * @since 3.0 + */ + +#include <odemx/data/SimRecordFilter.h> + +#include <algorithm> +#include <iterator> +#include <sstream> + +namespace odemx { +namespace data { + +//------------------------------------------------------construction/destruction + +std::shared_ptr< SimRecordFilter > SimRecordFilter::create() +{ + return std::shared_ptr< SimRecordFilter >( new SimRecordFilter() ); +} + +SimRecordFilter::SimRecordFilter() +{ +} + +SimRecordFilter::~SimRecordFilter() +{ +} + +} } // namespace odemx::data diff --git a/odemx-lite/src/data/buffer/SimRecordBuffer.cpp b/odemx-lite/src/data/buffer/SimRecordBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdae1fd82c61e191034c131c9bdd13693188c311 --- /dev/null +++ b/odemx-lite/src/data/buffer/SimRecordBuffer.cpp @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file SimRecordBuffer.cpp + * @author Ronald Kluth + * @date created at 2009/09/14 + * @brief Implementation of class odemx::data::SimRecordBuffer + * @sa SimRecordBuffer.h + * @since 3.0 + */ + +#include <odemx/data/buffer/SimRecordBuffer.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/Producer.h> + +namespace odemx { +namespace data { +namespace buffer { + +SimRecordBuffer::SimRecordBuffer( SizeType limit ) +: storage_() +, size_( 0 ) +, limit_( limit ) +{ +} + +void SimRecordBuffer::put( const Log::ChannelId channelId, + const SimRecord& simRecord, const TableKey simId, + const std::string& timeString ) +{ + const Producer& sender = simRecord.getSender(); + + // copy volatile and additional information and store it as InfoType + StoredRecord record( simRecord.getText(), simRecord.getDetailPointer() ); + record + + ChannelInfo( channel_id::toString( channelId ) ) + + SenderLabelInfo( sender.getLabel() ) + + SenderTypeInfo( sender.getType().toString() ) + + StringTimeInfo( timeString ) + + SimIdInfo( simId ); + + if( simRecord.hasScope() ) + { + record + ClassScopeInfo( simRecord.getScope().toString() ); + } + + // store the extended record + storage_.push_back( record ); + ++size_; +} + +void SimRecordBuffer::clear() +{ + storage_.clear(); + size_ = 0; +} + +bool SimRecordBuffer::isEmpty() const +{ + return size_ == 0; +} + +bool SimRecordBuffer::isFull() const +{ + return size_ >= limit_; +} + +const SimRecordBuffer::StorageType& SimRecordBuffer::getStorage() const +{ + return storage_; +} + +SimRecordBuffer::SizeType SimRecordBuffer::getSize() const +{ + return size_; +} + +SimRecordBuffer::SizeType SimRecordBuffer::getLimit() const +{ + return limit_; +} + +} } } // namespace odemx::data diff --git a/odemx-lite/src/data/buffer/StatisticsBuffer.cpp b/odemx-lite/src/data/buffer/StatisticsBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6f50832625b582c7357be15e4a04bdee359c5fa --- /dev/null +++ b/odemx-lite/src/data/buffer/StatisticsBuffer.cpp @@ -0,0 +1,306 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file StatisticsBuffer.cpp + * @author Ronald Kluth + * @date created at 2009/04/07 + * @brief Implementation of class odemx::data::buffer::StatisticsBuffer + * @sa StatisticsBuffer.h + * @since 3.0 + */ + +#include <odemx/data/buffer/StatisticsBuffer.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/Producer.h> +#include <odemx/data/Report.h> +#include <odemx/util/Exceptions.h> +#include <odemx/util/StringConversion.h> + +namespace odemx { +namespace data { +namespace buffer { + +//------------------------------------------------------construction/destruction + +std::shared_ptr< StatisticsBuffer > StatisticsBuffer::create( + base::Simulation& sim, const Label& label, bool bufferUpdates ) +{ + return std::shared_ptr< StatisticsBuffer >( + new StatisticsBuffer( sim, label, bufferUpdates ) ); +} + +StatisticsBuffer::StatisticsBuffer( base::Simulation& sim, const Label& label, + bool bufferUpdates ) +: ReportProducer( sim, label ) +, statistics_() +, bufferUpdates_( bufferUpdates ) +{ +} + +StatisticsBuffer::~StatisticsBuffer() +{ +} + +//---------------------------------------------------------------------accessors + +const StatisticsBuffer::StatisticsMap& StatisticsBuffer::getStatistics() const +{ + return statistics_; +} + +/// Check for existing ProducerStats or create and add a new stats object +StatisticsBuffer::ProducerStatsPtr StatisticsBuffer::getObjectStats( + const data::Producer& sender ) +{ + ProducerStatsPtr objectStats; + StatisticsMap::iterator found = statistics_.find( sender.getLabel() ); + if( found != statistics_.end() ) + { + objectStats = found->second; + } + else + { + objectStats.reset( new ProducerStats() ); + statistics_[ sender.getLabel() ] = objectStats; + objectStats->resetTime = 0; + } + + // store the sender type for report output + if( ! objectStats->senderType.isSet() ) + { + objectStats->senderType = sender.getType(); + } + return objectStats; +} + +bool StatisticsBuffer::isBufferingUpdates() const +{ + return bufferUpdates_; +} + +const StatisticsBuffer::UpdateDeque& StatisticsBuffer::getUpdates( + const Label& producer, const StringLiteral& property ) const +{ + StatisticsMap::const_iterator found = statistics_.find( producer ); + + if( found != statistics_.end() ) + { + UpdateMap::const_iterator foundProp = + found->second->updateStats.find( property ); + + if( foundProp != found->second->updateStats.end() ) + { + return foundProp->second.updates; + } + else + { + throw DataException( "StatisticsBuffer::getUpdates(): property not found" ); + } + } + else + { + throw DataException( "StatisticsBuffer::getUpdates(): producer not found" ); + } +} + +bool StatisticsBuffer::isEmpty() const +{ + return statistics_.empty(); +} + +void StatisticsBuffer::reset( base::SimTime resetTime ) +{ + for( StatisticsMap::iterator iter = statistics_.begin(); + iter != statistics_.end(); ++iter ) + { + ProducerStatsPtr objectStats = iter->second; + objectStats->resetTime = resetTime; + CountMap empty1; + UpdateMap empty2; + objectStats->countStats.swap( empty1 ); + objectStats->updateStats.swap( empty2 ); + } +} + +//---------------------------------------------------------------record handling + +void StatisticsBuffer::consume( const Log::ChannelId channelId, const SimRecord& record ) +{ + // ignore log records from other channels + if( channelId != channel_id::statistics ) + { + return; + } + + const data::StringLiteral& recordType = record.getText(); + const data::Producer& sender = record.getSender(); + base::SimTime time = record.getTime(); + + // check the statistics record type and choose the appropriate action + if( recordType == "parameter" ) + { + ProducerStatsPtr objectStats = getObjectStats( sender ); + const SimRecord::DetailVec& details = record.getDetails(); + for( SimRecord::DetailVec::const_iterator iter = details.begin(); + iter != details.end(); ++iter ) + { + // save parameter name and value + objectStats->paramStats[ iter->first ] = iter->second; + } + } + else if( recordType == "count" ) + { + ProducerStatsPtr objectStats = getObjectStats( sender ); + const SimRecord::DetailVec& details = record.getDetails(); + for( SimRecord::DetailVec::const_iterator iter = details.begin(); + iter != details.end(); ++iter ) + { + // add the given value to the counter + objectStats->countStats[ iter->first ] += iter->second.as<std::size_t>(); + } + } + else if( recordType == "update" ) + { + ProducerStatsPtr objectStats = getObjectStats( sender ); + const SimRecord::DetailVec& details = record.getDetails(); + for( SimRecord::DetailVec::const_iterator iter = details.begin(); + iter != details.end(); ++iter ) + { + const Log::StringLiteral& property = iter->first; + + // get the updated property + UpdateMap::iterator updateIter = objectStats->updateStats.find( property ); + if( updateIter == objectStats->updateStats.end() ) + { + // create new update stats if necessary + std::pair< UpdateMap::iterator, bool> result = + objectStats->updateStats.insert( + UpdateMap::value_type( property, + UpdateStats( const_cast< base::Simulation& >( sender.getSimulation() ), + sender.getLabel() + " " + property.c_str() ) ) ); + assert( result.second ); + updateIter = result.first; + } + // get reference to the update stats which must exist now + UpdateStats& updateStats = updateIter->second; + // store the update time and value and accumulate statistics + double value = iter->second.as<double>(); + // compute accumulated value + updateStats.accumulate.update( time, value ); + // store updates, if enabled + if( bufferUpdates_ ) + { + updateStats.updates.push_back( std::make_pair( time, value ) ); + } + } + } + else if( recordType == "reset" ) + { + ProducerStatsPtr objectStats = getObjectStats( sender ); + objectStats->resetTime = time; + CountMap empty1; + UpdateMap empty2; + objectStats->countStats.swap( empty1 ); + objectStats->updateStats.swap( empty2 ); + } +} + +void StatisticsBuffer::report( data::Report& report ) +{ + using namespace data; + + // iterate over the statistics data of all senders + for( StatisticsMap::const_iterator iter = statistics_.begin(); + iter != statistics_.end(); ++iter ) + { + const Label& sender = iter->first; + const buffer::StatisticsBuffer::ProducerStatsPtr objectStats = iter->second; + + if( ! ( objectStats->paramStats.empty() && objectStats->countStats.empty() ) ) + { + ReportTable::Definition paramCountTableDef; + + // build table definition for param and counter table + paramCountTableDef.addColumn( "Name", ReportTable::Column::STRING ); + paramCountTableDef.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + + for( ParamMap::iterator paramIter = objectStats->paramStats.begin(); + paramIter != objectStats->paramStats.end(); ++paramIter ) + { + paramCountTableDef.addColumn( paramIter->first.c_str(), ReportTable::Column::STRING ); + } + + for( CountMap::iterator countIter = objectStats->countStats.begin(); + countIter != objectStats->countStats.end(); ++countIter ) + { + paramCountTableDef.addColumn( countIter->first.c_str(), ReportTable::Column::INTEGER ); + } + + // tables are associated with sender types + ReportTable& table = report.getTable( + objectStats->senderType.toString(), paramCountTableDef ); + + table << sender << objectStats->resetTime; + + for( ParamMap::iterator paramIter = objectStats->paramStats.begin(); + paramIter != objectStats->paramStats.end(); ++paramIter ) + { + table << static_cast<const std::string&>(paramIter->second); + } + + for( CountMap::iterator countIter = objectStats->countStats.begin(); + countIter != objectStats->countStats.end(); ++countIter ) + { + table << countIter->second; + } + } + + // define accum table + ReportTable::Definition def; + def.addColumn( "Producer", ReportTable::Column::STRING ); + def.addColumn( "Property", ReportTable::Column::STRING ); + def.addColumn( "Updates", ReportTable::Column::INTEGER ); + def.addColumn( "Min", ReportTable::Column::REAL ); + def.addColumn( "Max", ReportTable::Column::REAL ); + def.addColumn( "Mean", ReportTable::Column::REAL ); + def.addColumn( "Weighted Mean", ReportTable::Column::REAL ); + def.addColumn( "Std Deviation", ReportTable::Column::REAL ); + def.addColumn( "Weighted StDev", ReportTable::Column::REAL ); + ReportTable& table = report.getTable( "odemx::data::buffer::StatisticsBuffer Updates", def ); + + // print accum stats + for( UpdateMap::iterator updateIter = objectStats->updateStats.begin(); + updateIter != objectStats->updateStats.end(); ++updateIter ) + { + const statistics::Accumulate& accum = updateIter->second.accumulate; + table + << sender + << updateIter->first.c_str() + << accum.getUpdateCount() + << accum.getMin() + << accum.getMax() + << accum.getMean() + << accum.getWeightedMean() + << accum.getStandardDeviation() + << accum.getWeightedStandardDeviation(); + } + } +} + +} } } // namespace odemx::data::buffer diff --git a/odemx-lite/src/data/output/ErrorWriter.cpp b/odemx-lite/src/data/output/ErrorWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b25d793156094a3daafc8fb5637a7fd156281dcc --- /dev/null +++ b/odemx-lite/src/data/output/ErrorWriter.cpp @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ErrorWriter.cpp + * @author Ronald Kluth + * @date created at 2009/09/30 + * @brief Implementation of class odemx::data::output::ErrorWriter + * @sa ErrorWriter.h + * @since 3.0 + */ + +#include <odemx/data/output/ErrorWriter.h> +#include <odemx/data/output/DefaultTimeFormat.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/Producer.h> + +#include <iostream> +#include <iomanip> + +namespace odemx { +namespace data { +namespace output { + +//------------------------------------------------------construction/destruction + +std::shared_ptr< ErrorWriter > ErrorWriter::create() +{ + return std::shared_ptr< ErrorWriter >( new ErrorWriter() ); +} + +ErrorWriter::ErrorWriter() +: format_( new DefaultTimeFormat() ) +{ +} + +ErrorWriter::~ErrorWriter() +{ +} + +//---------------------------------------------------------------record handling + +void ErrorWriter::consume( const Log::ChannelId channelId, const SimRecord& record ) +{ + using namespace std; + + switch( channelId ) + { + case channel_id::warning: cerr << "ODEMx WARNING: "; break; + case channel_id::error: cerr << "ODEMx ERROR: "; break; + case channel_id::fatal: cerr << "ODEMx FATAL ERROR: "; break; + default: + cerr << "ODEMx ERROR: ErrorWriter::consume(): " + "connected to wrong log channel" << endl; + return; + } + + const Producer& sender = record.getSender(); + + cerr + << record.getText() + << " [Time: " << format_->timeToString( record.getTime() ) + << "] [Object: " << sender << " (" << sender.getType().toString() << ")]"; + + if( record.hasDetails() ) + { + cerr << " ["; + for( SimRecord::DetailVec::const_iterator detail = record.getDetails().begin(); + detail != record.getDetails().end(); ++detail ) + { + if( detail != record.getDetails().begin() ) + { + cerr << " | "; + } + cerr << detail->first << "=" + << detail->second.as<std::string>(); + } + cerr << "]"; + } + + if( record.hasScope() ) + { + cerr << " [Scope: " << record.getScope().toString() << "]"; + } + + cerr << std::endl; +} + +//-----------------------------------------------------------------------setters + +void ErrorWriter::setTimeFormat( TimeFormat* timeFormat ) +{ + format_.reset( timeFormat ); +} + +} } } // namespace odemx::data::output diff --git a/odemx-lite/src/data/output/GermanTime.cpp b/odemx-lite/src/data/output/GermanTime.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdf385d8be923eb9eeb525f49847bc32b24f9830 --- /dev/null +++ b/odemx-lite/src/data/output/GermanTime.cpp @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file GermanTime.cpp + * @author Ronald Kluth + * @date created at 2009/04/03 + * @brief Implementation of class odemx::data::output::GermanTime + * @sa GermanTime.h + * @since 2.1 + */ + +#include <odemx/data/output/GermanTime.h> +#include <odemx/data/output/TimeBase.h> +#include <odemx/data/output/TimeUnit.h> + +#include <iomanip> +#include <string> +#include <sstream> + +namespace odemx { +namespace data { +namespace output { + +//------------------------------------------------------construction/destruction + +GermanTime::GermanTime() +: TimeFormat() +{ +} + +GermanTime::GermanTime( const TimeBase& base ) +: TimeFormat( base ) +{ +} + +//----------------------------------------------------------time string creation + +const std::string GermanTime::makeString() const +{ + using namespace std; + + ostringstream stream; + stream.fill('0'); + + if( (year - 100) > 0 ) + { + stream << setw(4) << year; + } + else + { + stream << setw(2) << year; + } + + stream << '-' << setw(2) << month << '-'; + stream << setw(2) << day; + + stream << " / "; + stream << setw(2) << hour << ':'; + stream << setw(2) << min; + + if( base.unit == TimeUnit::milliseconds ) + { + stream << ':' << setw(6) << fixed << setprecision(3) << sec; + } + else + { + stream << ':' << setw(2) << fixed << setprecision(0) << sec; + } + return stream.str(); +} + +} } } // namespace odemx::data::output diff --git a/odemx-lite/src/data/output/Iso8601Time.cpp b/odemx-lite/src/data/output/Iso8601Time.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cf95b1c2d71efedb7d98c0318c352af1d6b2ab4 --- /dev/null +++ b/odemx-lite/src/data/output/Iso8601Time.cpp @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Iso8601Time.cpp + * @author Ronald Kluth + * @date created at 2009/04/03 + * @brief Implementation of class odemx::data::output::Iso8601Time + * @sa Iso8601Time.h + * @since 2.1 + */ + +#include <odemx/data/output/Iso8601Time.h> + +#include <cmath> +#include <iomanip> +#include <string> +#include <sstream> +#include <stdexcept> + +namespace odemx { +namespace data { +namespace output { + +//------------------------------------------------------construction/destruction + +Iso8601Time::Iso8601Time( const TimeBase& base, short utcOffsetHour, unsigned short utcOffsetMin ) +: TimeFormat( base ) +, utcOffset_( UtcOffset( utcOffsetHour, utcOffsetMin ) ) +{ +} + +//----------------------------------------------------------time string creation + +const std::string Iso8601Time::makeString() const +{ + using namespace std; + + ostringstream stream; + stream.fill('0'); + + stream + << setw(4) << year << '-' + << setw(2) << month << '-' + << setw(2) << day + << 'T' + << setw(2) << hour << ':' + << setw(2) << min; + + // print seconds or milliseconds + if( base.unit == TimeUnit::milliseconds ) + { + stream << ':' << setw(6) << fixed << setprecision(3) << sec; + } + else + { + stream << ':' << setw(2) << fixed << setprecision(0) << sec; + } + + // print UTC time zone + if( utcOffset_.hour || utcOffset_.minute ) + { + stream + << ( utcOffset_.hour > 0 ? '+' : '-' ) + << setw(2) << setprecision(0) + << std::abs( static_cast< float >( utcOffset_.hour ) ) << ':' + << setw(2) << utcOffset_.minute; + } + else + { + stream << 'Z'; // represents UTC-0 + } + + return stream.str(); +} + +//--------------------------------------------------------------------UTC offset + +Iso8601Time::UtcOffset::UtcOffset( short h, unsigned short m ) +{ + if ( h || m ) + { + if( h < -12 || h > 14 ) + { + throw std::out_of_range( + "TimeZone(): hour value range is -12 through 14" ); + } + if( ! ( m == 0 || m == 15 || m == 30 || m == 45 ) ) + { + throw std::out_of_range( + "TimeZone(): minute requires values 0, 15, 30, or 45" ); + } + } + hour = h; + minute = m; +} + +void Iso8601Time::setUtcOffset( short hour, short minute ) +{ + utcOffset_ = UtcOffset( hour, minute ); +} + +const Iso8601Time::UtcOffset& Iso8601Time::getUtcOffset() const +{ + return utcOffset_; +} + +} } } // namespace odemx::data::output diff --git a/odemx-lite/src/data/output/OStreamReport.cpp b/odemx-lite/src/data/output/OStreamReport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1aeca9e0361a6d681351beb6c029f607143f111 --- /dev/null +++ b/odemx-lite/src/data/output/OStreamReport.cpp @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file OStreamReport.cpp + * @author Ronald Kluth + * @date created at 2009/02/28 + * @brief Implementation of class odemx::data::output::OStreamReport + * @sa OStreamReport.h + * @since 3.0 + */ + +#include <odemx/data/output/OStreamReport.h> +#include <odemx/data/buffer/StatisticsBuffer.h> + +#include <iomanip> + +namespace odemx { +namespace data { +namespace output { + +OStreamReport::OStreamReport( std::ostream& os ) +: os_( os ) +{ +} + +OStreamReport::~OStreamReport() +{ +} + +void OStreamReport::startProcessing() +{ + os_ << "ODEMx Statistics Report\n" + << "======================="; +} + +void OStreamReport::endProcessing() +{ +} + +void OStreamReport::processTables() +{ + using namespace std; + + if( tables_.empty() ) + { + os_ << "\n\n" << "no statistics tables to display\n"; + return; + } + + // write tables + for( TableVec::const_iterator iter = tables_.begin(); + iter != tables_.end(); ++iter ) + { + ReportTable* table = *iter; + + if( ! table ) + { + continue; + } + + // title + os_ << "\n\n" << table->getLabel() << "\n"; + os_ << string( table->getLabel().length(), '-' ) << "\n"; + os_ << left; + + // compute column widths + std::deque< std::size_t > colWidths( table->getNumberOfColumns(), 0 ); + + for( ReportTable::SizeType col = 0; col < table->getNumberOfColumns(); ++col ) + { + for( ReportTable::SizeType line = 0; line < table->getNumberOfLines(); ++line ) + { + std::size_t currentWidth = 0; + switch( table->getTypeOfColumn( col ) ) + { + case ReportTable::Column::REAL: // fall through + case ReportTable::Column::STRING: + case ReportTable::Column::INTEGER: + case ReportTable::Column::SIMTIME: + currentWidth = table->getSTRING( col, line ).size(); + break; + case ReportTable::Column::BAR: + { + long barSize = table->getBAR( col, line ); + if( barSize < 0 ) + { + currentWidth = 0; + } + else + { + currentWidth = barSize; + } + break; + } + default: + break; + } + // store max value + colWidths[ col ] = std::max( colWidths[ col ], currentWidth ); + colWidths[ col ] = std::max( colWidths[ col ], table->getLabelOfColumn( col ).size() ); + } + + } + + // write column labels + for( ReportTable::SizeType i = 0; i < table->getNumberOfColumns(); ++i ) + { + os_ << setw( colWidths[ i ] ) + << table->getLabelOfColumn( i ) + << " | "; + } + + // write lines + for( ReportTable::SizeType line = 0; line < table->getNumberOfLines(); ++line ) + { + os_ << "\n"; + + // write cells + for( ReportTable::SizeType col = 0; col < table->getNumberOfColumns(); ++col ) + { + switch( table->getTypeOfColumn( col ) ) + { + case ReportTable::Column::REAL: // fall through + case ReportTable::Column::STRING: + case ReportTable::Column::INTEGER: + case ReportTable::Column::SIMTIME: + os_ << setw( colWidths[ col ] ) + << table->getSTRING( col, line ) + << " | "; + break; + case ReportTable::Column::BAR: + { + long barSize = table->getBAR( col, line ); + if( barSize > 0 ) + { + os_ << left << string( table->getBAR( col, line ), '*' ); + } + break; + } + default: + break; + } + } + } + } + os_ << "\n" << endl; +} + +} } } // namespace odemx::data::output diff --git a/odemx-lite/src/data/output/OStreamWriter.cpp b/odemx-lite/src/data/output/OStreamWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a68c3ecd25ed1b9ea9a2f0d799f786579cb2c402 --- /dev/null +++ b/odemx-lite/src/data/output/OStreamWriter.cpp @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file OStreamWriter.cpp + * @author Ronald Kluth + * @date created at 2009/02/09 + * @brief Implementation of class odemx::data::output::OStreamWriter + * @sa OStreamWriter.h + * @since 3.0 + */ + +#include <odemx/data/output/OStreamWriter.h> +#include <odemx/data/output/DefaultTimeFormat.h> +#include <odemx/data/ManagedChannels.h> +#include <odemx/data/Producer.h> + +#include <iomanip> + +namespace odemx { +namespace data { +namespace output { + +//------------------------------------------------------construction/destruction + +std::shared_ptr< OStreamWriter > OStreamWriter::create( std::ostream& os ) +{ + return std::shared_ptr< OStreamWriter >( new OStreamWriter( os ) ); +} + +OStreamWriter::OStreamWriter( std::ostream& os ) +: os_( os ) +, format_( new DefaultTimeFormat() ) +{ + os_ << "ODEMx Log\n" + << "=========\n"; +} + +OStreamWriter::~OStreamWriter() +{ +} + +//---------------------------------------------------------------record handling + +void OStreamWriter::consume( const Log::ChannelId channelId, const SimRecord& record ) +{ + using namespace std; + + std::string timeString = format_->timeToString( record.getTime() ); + const Producer& sender = record.getSender(); + + os_ + << timeString << " " + << channel_id::toString( channelId ) << ": " + << sender.getLabel() << "(" << sender.getType().toString() << ") " + << record.getText(); + + if( record.hasDetails() ) + { + os_ << " ["; + for( SimRecord::DetailVec::const_iterator detail = record.getDetails().begin(); + detail != record.getDetails().end(); ++detail ) + { + if( detail != record.getDetails().begin() ) + { + os_ << " | "; + } + os_ << detail->first << "=" + << detail->second.as<std::string>(); + } + os_ << "]"; + } + + if( record.hasScope() ) + { + os_ << " [Class Scope: " << record.getScope().toString() << "]"; + } + + os_ << std::endl; +} + +//-----------------------------------------------------------------------setters + +void OStreamWriter::setTimeFormat( TimeFormat* timeFormat ) +{ + format_.reset( timeFormat ); +} + +} } } // namespace odemx::data::output diff --git a/odemx-lite/src/data/output/TimeFormat.cpp b/odemx-lite/src/data/output/TimeFormat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73ed78175fe18eab0b63653c90be6457faa44a5d --- /dev/null +++ b/odemx-lite/src/data/output/TimeFormat.cpp @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file TimeFormat.cpp + * @author Ronald Kluth + * @date created at 2008/03/14 + * @brief Implementation of odemx::data::output::TimeFormat + * @sa TimeFormat.h + * @since 2.1 + */ + +#if defined(_MSC_VER) +#pragma warning(disable : 4244) // conversion of SimTime to double possible data loss +#endif + +#include <odemx/data/output/TimeFormat.h> +#include <odemx/util/Exceptions.h> + +#include <cmath> +#include <cassert> +#include <iomanip> +#include <stdexcept> + +namespace odemx { +namespace data { +namespace output { + +//------------------------------------------------------construction/destruction + +TimeFormat::TimeFormat() +: base( 0, 0, 0, static_cast< base::SimTime >(0), TimeUnit::none ) +{ + resetTimeValues(); +} + +TimeFormat::TimeFormat( const TimeBase& timeBase ) +: base( timeBase ) +{ + resetTimeValues(); +} + +TimeFormat::~TimeFormat() +{ +} + +//-----------------------------------------------------------------------setters + +void TimeFormat::setTimeBase( unsigned short year, unsigned short month, + unsigned short day, base::SimTime dayTimeOffset, TimeUnit::Type unit ) +{ + base.year = year; + base.month = month; + base.day = day; + base.offset = dayTimeOffset; + base.unit = unit; +} + +void TimeFormat::setTimeBase( const TimeBase& timeBase ) +{ + base = timeBase; +} + +void TimeFormat::resetTimeValues() +{ + simTime = static_cast< base::SimTime >(0); + year = month = day = hour = min = 0; + sec = 0.0; +} + +//-----------------------------------------------------------------------getters + +const TimeBase& TimeFormat::getTimeBase() const +{ + return base; +} + +//-------------------------------------------------------------string conversion + +const std::string TimeFormat::timeToString( base::SimTime time ) +{ + computeTimeValues( time ); + return makeString(); +} + +unsigned short TimeFormat::daysOfMonth( unsigned short month, unsigned short year ) +{ + bool leapYear = false; + + if( year % 4 == 0 ) leapYear = true; + if( year % 100 == 0 ) leapYear = false; + if( year % 400 == 0 ) leapYear = true; + + switch( month ) + { + case 4: + case 6: + case 9: + case 11: + return 30; + + case 2: + return leapYear ? 29 : 28; + + default: + return 31; + } +} + +void TimeFormat::computeTimeValues( base::SimTime time ) +{ + resetTimeValues(); + + if( getTimeBase().unit == TimeUnit::none ) + { + throw DataException( "TimeFormat::computeTimeValues():" + " cannot compute time, no base unit given" ); + } + + // store the SimTime in minutes for easy computation + double simMinutes = 0.0; + // store the daytime offset + double dayTimeOffset = 0.0; + + // convert SimTime to minutes for convenience + // by evaluating the given Time::unit of the Format definition + switch( getTimeBase().unit ) + { + case TimeUnit::milliseconds: + simMinutes = time / double(60000); + dayTimeOffset = getTimeBase().offset / double(60000); + break; + + case TimeUnit::seconds: + simMinutes = time / double(60); + dayTimeOffset = getTimeBase().offset / double(60); + break; + + case TimeUnit::minutes: + simMinutes = time; + dayTimeOffset = getTimeBase().offset; + break; + + case TimeUnit::hours: + simMinutes = time * 60; + dayTimeOffset = getTimeBase().offset * 60; + break; + + case TimeUnit::none: + assert(false); + } + + // compute number of days from minutes + day = (unsigned short) floor( simMinutes / 1440.0 ); // 24h * 60' = 1440' + // subtract days from minutes to get the day time + simMinutes = simMinutes - ( day * 1440.0 ); + + // add time base data representing the starting point of the simulation + year += getTimeBase().year; + month += getTimeBase().month; + day += getTimeBase().day; + simMinutes += dayTimeOffset; + + // increase number of days if offset addition put minutes over 1440 + while( simMinutes > 1440.0 ) + { + ++day; + simMinutes -= 1440.0; + } + + // determine month and year + while( day > daysOfMonth( month, year ) ) + { + day -= daysOfMonth( month, year ); + ++month; + + if( month > 12 ) + { + month = 1; + ++year; + } + } + + // compute the day time in hours, minutes, seconds and milliseconds + hour = (unsigned short) floor( simMinutes / 60.0 ); + simMinutes -= hour * 60.0; + + // get minutes integer value + min = (unsigned short) floor( simMinutes ); + + // get seconds with milliseconds as double value + sec = ( simMinutes - min ) * 60.0; +} + +} } } // namespace odemx::data::output diff --git a/odemx-lite/src/protocol/Device.cpp b/odemx-lite/src/protocol/Device.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3cbd2a8d9ff0bd0ed2ee0c6b7cbbe263d2a77b0 --- /dev/null +++ b/odemx-lite/src/protocol/Device.cpp @@ -0,0 +1,273 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Device.cpp + * @author Ronald Kluth + * @date created at 2009/10/31 + * @brief Implementation of class odemx::protocol::Device + * @sa Device.h + * @since 3.0 + */ + +#include <odemx/protocol/Device.h> +#include <odemx/protocol/Layer.h> +#include <odemx/protocol/Medium.h> +#include <odemx/protocol/Sap.h> +#include <odemx/protocol/Pdu.h> +#include <odemx/synchronization/Timer.h> + +namespace odemx { +namespace protocol { + +Device::Device( base::Simulation& sim, const data::Label& label ) +: ServiceProvider( sim, label ) +, receiveSap_( 0 ) +, address_() +, medium_( 0 ) +, transmissionCount_( 0 ) +, collisionDetection_( sim, label + " collision detection", synchronization::IMemory::COLLISION_DETECTION ) +, collisionOccurred_( false ) +{ + receiveSap_ = addSap( "odemx_internal_device_receive_SAP" ); + assert( receiveSap_ ); +} + +Device::~Device() +{ +} + +void Device::setAddress( const AddressType& addr ) +{ + ODEMX_TRACE << log( "set address" ) + .detail( "value", addr ) + .scope( typeid(Device) ); + + address_ = addr; +} + +const Device::AddressType& Device::getAddress() const +{ + return address_; +} + +void Device::setMedium( Medium& medium ) +{ + if( medium_ && medium_ != &medium ) + { + error << log( "Device::setMedium():" + "attempt to register device with another medium" ) + .scope( typeid(Device) ); + } + else + { + ODEMX_TRACE << log( "set medium" ) + .detail( "label", medium.getLabel() ) + .scope( typeid(Device) ); + + medium_ = &medium; + } +} + +void Device::resetMedium() +{ + medium_ = 0; +} + +bool Device::hasMedium() const +{ + return medium_ != 0; +} + +bool Device::busy() const +{ + return transmissionCount_ >= 1; +} + +void Device::incTransmissionCount() +{ + ++transmissionCount_; + + ODEMX_TRACE << log( "increase transmission count" ) + .detail( "value", transmissionCount_ ) + .scope( typeid(Device) ); + + if( transmissionCount_ > 1 ) + { + collisionOccurred_ = true; + collisionDetection_.alert(); + + ODEMX_TRACE << log( "collision occurred" ).scope( typeid(Device) ); + + assert( medium_ ); + medium_->collision(); + } +} + +void Device::decTransmissionCount() +{ + if( transmissionCount_ > 0 ) + { + --transmissionCount_; + } + + ODEMX_TRACE << log( "decrease transmission count" ) + .detail( "value", transmissionCount_ ) + .scope( typeid(Device) ); +} + +unsigned int Device::getTransmissionCount() const +{ + return transmissionCount_; +} + +bool Device::hasCollisionDetection() +{ + return false; +} + +void Device::startTransmission() +{ + ODEMX_TRACE << log( "start transmission" ).scope( typeid(Device) ); + + medium_->signalTransmissionStart( this ); +} + +void Device::endTransmission( PduPtr p ) +{ + ODEMX_TRACE << log( "end transmission" ).scope( typeid(Device) ); + + medium_->signalTransmissionEnd( this, p ); +} + +bool Device::send( PduPtr p ) +{ + if( ! medium_ ) + { + error << log( "Device::transmit(): device not connected to a medium" ) + .scope( typeid( Device ) ); + return false; + } + + if( busy() ) + { + ODEMX_TRACE << log( "medium busy" ).scope( typeid(Device) ); + + return false; + } + + ODEMX_TRACE << log( "send" ).scope( typeid(Device) ); + + // start transmission + incTransmissionCount(); + collisionOccurred_ = false; + + base::SimTime duration = computeTransmissionDuration( p->getSize() ); + synchronization::Timer durationTimer( getSimulation(), getLabel() + " duration timer" ); + durationTimer.setIn( duration ); + + startTransmission(); + + synchronization::IMemory* alerter = 0; + + if( hasCollisionDetection() ) + { + alerter = Process::wait( &durationTimer, &collisionDetection_ ); + } + else + { + alerter = Process::wait( &durationTimer ); + } + + if( ! alerter ) + { + warning << log( "Device::send(): wait state ended by non-memory object" ) + .scope( typeid(Device) ); + } + + // detected collision, end transmission + // in the first case, the waking time is just earlier + // invalid data is sent in any case + if( alerter == &collisionDetection_ || collisionOccurred_ ) + { + if( alerter == &collisionDetection_ ) + { + ODEMX_TRACE << log( "collision detected" ).scope( typeid(Device) ); + } + else + { + ODEMX_TRACE << log( "collision occurred" ).scope( typeid(Device) ); + } + endTransmission( PduPtr() ); + decTransmissionCount(); + return false; + } + + // transmission finished + endTransmission( p ); + decTransmissionCount(); + + ODEMX_TRACE << log( "transmission succeeded" ).scope( typeid(Device) ); + + return true; +} + +void Device::handleInput( const std::string& sapName, PduPtr p ) +{ + if( sapName == receiveSap_->getName() ) + { + ODEMX_TRACE << log( "handle receive" ).scope( typeid(Device) ); + + handleReceive( p ); + } + else + { + ODEMX_TRACE << log( "handle send" ).scope( typeid(Device) ); + + handleSend( sapName, p ); + } +} + + /// Pass a message to the service user, i.e. to the upper layer via the device's SAP +void Device::pass( const std::string& upperLayerSap, PduPtr p ) +{ + Sap* sap = getLayer()->getUpperLayer()->getSap( upperLayerSap ); + if( sap ) + { + ODEMX_TRACE << log( "pass" ) + .detail( "SAP", upperLayerSap ) + .scope( typeid(Device) ); + + sap->write( p ); + } + else + { + warning << log( "Device::pass(): upper layer does not offer SAP" ) + .detail( "name", upperLayerSap ) + .scope( typeid(Device) ); + } +} + +void Device::receive( PduPtr p ) +{ + ODEMX_TRACE << log( "receive" ).scope( typeid(Device) ); + + receiveSap_->write( p ); +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/Entity.cpp b/odemx-lite/src/protocol/Entity.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a664b0358a1a801c1d3d514a00ce1c816b04cbe --- /dev/null +++ b/odemx-lite/src/protocol/Entity.cpp @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Entity.cpp + * @author Ronald Kluth + * @date created at 2009/10/13 + * @brief Implementation of class odemx::protocol::Entity + * @sa Entity.h + * @since 3.0 + */ + +#include <odemx/protocol/Entity.h> +#include <odemx/protocol/Layer.h> + +namespace odemx { +namespace protocol { + +Entity::Entity( base::Simulation& sim, const data::Label& label ) +: ServiceProvider( sim, label ) +{ +} + +Entity::~Entity() +{ +} + +void Entity::send( const std::string& lowerLayerSap, PduPtr p ) +{ + Sap* sap = getLayer()->getLowerLayer()->getSap( lowerLayerSap ); + if( sap ) + { + ODEMX_TRACE << log( "send" ) + .detail( "SAP", lowerLayerSap ) + .scope( typeid(Entity) ); + + sap->write( p ); + } + else + { + warning << log( "Entity::send(): lower layer does not offer SAP" ) + .detail( "name", lowerLayerSap ) + .scope( typeid(Entity) ); + } +} + +void Entity::pass( const std::string& upperLayerSap, PduPtr p ) +{ + Sap* sap = getLayer()->getUpperLayer()->getSap( upperLayerSap ); + if( sap ) + { + ODEMX_TRACE << log( "pass" ) + .detail( "SAP", upperLayerSap ) + .scope( typeid(Entity) ); + + sap->write( p ); + } + else + { + warning << log( "Entity::pass(): upper layer does not offer SAP" ) + .detail( "name", upperLayerSap ) + .scope( typeid(Entity) ); + } +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/ErrorModelDraw.cpp b/odemx-lite/src/protocol/ErrorModelDraw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3cb0493bc1e6175493ee119e31270bc38a792b75 --- /dev/null +++ b/odemx-lite/src/protocol/ErrorModelDraw.cpp @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ErrorModelDraw.cpp + * @author Ronald Kluth + * @date created at 2010/04/05 + * @brief Implementation of class odemx::protocol::ErrorModelDraw + * @sa ErrorModelDraw.h + * @since 3.0 + */ + +#include <odemx/protocol/ErrorModelDraw.h> + +namespace odemx { +namespace protocol { + +ErrorModelDraw::ErrorModelDraw( base::Simulation& sim, const data::Label& label, + double probability ) +: draw_( sim, label + " draw", probability ) +{} + +ErrorModelDraw::~ErrorModelDraw() +{ +} + +ErrorModelPtr ErrorModelDraw::create( base::Simulation& sim, const data::Label& label, + double probability ) +{ + return ErrorModelPtr( new ErrorModelDraw( sim, label, probability ) ); +} + +bool ErrorModelDraw::apply( PduPtr p ) +{ + return draw_.sample() == 1; +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/Layer.cpp b/odemx-lite/src/protocol/Layer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c100517db6cbd3ad23e2bee028f13035be6da99 --- /dev/null +++ b/odemx-lite/src/protocol/Layer.cpp @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Layer.cpp + * @author Ronald Kluth + * @date created at 2009/10/13 + * @brief Implementation of class odemx::protocol::Layer + * @sa Layer.h + * @since 3.0 + */ + +#include <odemx/protocol/Layer.h> +#include <odemx/protocol/Sap.h> +#include <odemx/protocol/ServiceProvider.h> +#include <odemx/util/DeletePtr.h> + +#include <algorithm> // for_each, find_if + +namespace odemx { +namespace protocol { + +Layer::Layer( base::Simulation& sim, const data::Label& label ) +: data::Producer( sim, label ) +, serviceProviders_() +, saps_() +, upperLayer_( 0 ) +, lowerLayer_( 0 ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Layer) ); +} + +Layer::~Layer() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Layer) ); + + std::for_each( + serviceProviders_.begin(), + serviceProviders_.end(), + DeletePtr< ServiceProvider >() ); +}; + +void Layer::addServiceProvider( ServiceProvider* sp ) +{ + assert( sp ); + + ODEMX_TRACE << log( "add service provider" ) + .detail( "label", sp->getLabel() ) + .scope( typeid(Layer) ); + + sp->setLayer( this ); + for( ServiceProvider::SapVec::const_iterator iter = sp->getSaps().begin(); + iter != sp->getSaps().end(); ++iter ) + { + addSap( *iter ); + } + serviceProviders_.push_back( sp ); +} + +void Layer::addSap( Sap* sap ) +{ + assert( sap ); + + std::pair< SapMap::iterator, bool > result = + saps_.insert( SapMap::value_type( sap->getName(), sap ) ); + + if( result.second ) + { + ODEMX_TRACE << log( "add SAP" ) + .detail( "name", sap->getName() ) + .scope( typeid(Layer) ); + } + else + { + warning << log( "Layer::addSap(): SAP already in map, insertion failed") + .detail( "name", sap->getName() ) + .scope( typeid(Layer) ); + } +} + +bool Layer::removeSap( const std::string& sap ) +{ + SapMap::iterator found = saps_.find( sap ); + + if( found != saps_.end() ) + { + ODEMX_TRACE << log( "remove SAP" ) + .detail( "name", sap ) + .scope( typeid(Layer) ); + + saps_.erase( found ); + return true; + } + else + { + warning << log( "Layer::removeSap(): SAP not found") + .detail( "name", sap ) + .scope( typeid(Layer) ); + } + return false; +} + +Sap* Layer::getSap( const std::string& sap ) const +{ + SapMap::const_iterator found = saps_.find( sap ); + + if( found != saps_.end() ) + { + return found->second; + } + return 0; +} + +Layer::SapMap& Layer::getSaps() +{ + return saps_; +} + +void Layer::setUpperLayer( Layer* layer ) +{ + upperLayer_ = layer; +} + +Layer* Layer::getUpperLayer() const +{ + return upperLayer_; +} + +void Layer::setLowerLayer( Layer* layer ) +{ + lowerLayer_ = layer; +} + +Layer* Layer::getLowerLayer() const +{ + return lowerLayer_; +} + +const Layer::ServiceProviderVec& Layer::getServiceProviders() const +{ + return serviceProviders_; +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/Medium.cpp b/odemx-lite/src/protocol/Medium.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33e8eb17c68ab17959a334bf0d1c1b44c237e871 --- /dev/null +++ b/odemx-lite/src/protocol/Medium.cpp @@ -0,0 +1,307 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Medium.cpp + * @author Ronald Kluth + * @date created at 2009/11/01 + * @brief Implementation of class odemx::protocol::Medium + * @sa Medium.h + * @since 3.0 + */ + +#include <odemx/protocol/Medium.h> +#include <odemx/protocol/Device.h> +#include <odemx/protocol/ErrorModel.h> +#include <odemx/protocol/Pdu.h> +#include <odemx/util/TypeToString.h> + +namespace odemx { +namespace protocol { + +//---------------------------------------------------------------------link info + +Medium::LinkInfo::LinkInfo() +{ +} + +Medium::LinkInfo::LinkInfo( base::SimTime delay, ErrorModelPtr errorModel ) +: delay_( delay ) +, errorModel_( errorModel ) +{ +} + +//-----------------------------------------------------------transmission events + +Medium::TransmissionStart::TransmissionStart( base::Simulation& sim, + const data::Label& label, Device& device ) +: Event( sim, label ) +, device_( &device ) +{ +} + +void Medium::TransmissionStart::eventAction() +{ + device_->incTransmissionCount(); +} + +Medium::TransmissionEnd::TransmissionEnd( base::Simulation& sim, + const data::Label& label, Device& device, PduPtr p ) +: Event( sim, label ) +, device_( &device ) +, pdu_( p ) +{ +} + +void Medium::TransmissionEnd::eventAction() +{ + device_->decTransmissionCount(); + if( pdu_ ) + { + device_->receive( pdu_ ); + } +} + +//------------------------------------------------------construction/destruction + +Medium::Medium( base::Simulation& sim, const data::Label& label ) +: Producer( sim, label ) +, topology_() +, defaultErrorModel_() +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Medium) ); +} + +Medium::~Medium() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Medium) ); +} + +void Medium::signalTransmissionStart( Device* device ) +{ + assert( device ); + + ODEMX_TRACE << log( "signal transmission start" ) + .detail( "device", device->getLabel() ) + .scope( typeid(Medium) ); + + LinkInfoMap& receivers = topology_[ device ]; + for( LinkInfoMap::const_iterator iter = receivers.begin(); + iter != receivers.end(); ++iter ) + { + // get the neighbor and the link properties + Device* peerDevice = iter->first; + const LinkInfo& link = iter->second; + + // ignore self-messaging + if( device == peerDevice ) + { + continue; + } + + // data is propagated if there is no error model for the link, + // or if the data passes the error model + base::Event* event = new TransmissionStart( getSimulation(), + "Transmission Start", *peerDevice ); + event->scheduleIn( link.delay_ ); + } +} + +void Medium::signalTransmissionEnd( Device* device, PduPtr p ) +{ + ODEMX_TRACE << log( "signal transmission end" ) + .detail( "device", device->getLabel() ) + .scope( typeid(Medium) ); + + LinkInfoMap& receivers = topology_[ device ]; + for( LinkInfoMap::const_iterator iter = receivers.begin(); + iter != receivers.end(); ++iter ) + { + statistics << count( "transmissions" ).scope( typeid(Medium) ); + + // get the neighbor and the link properties + Device* peerDevice = iter->first; + const LinkInfo& link = iter->second; + + // ignore self-messaging + if( device == peerDevice ) + { + continue; + } + + // the pdu gets clone + PduPtr clonePdu; + if( p ) + { + clonePdu = p->clone(); + } + + // data is propagated if there is no error model for the link, + // or if the data passes the error model + if( ! link.errorModel_ || link.errorModel_->apply( clonePdu ) ) + { + base::Event* event = new TransmissionEnd( getSimulation(), + "Transmission End", *peerDevice, clonePdu ); + event->scheduleIn( link.delay_ ); + + statistics << count( "deliveries" ).scope( typeid(Medium) ); + } + else // failed to pass error model, cannot not deliver no PDU + { + base::Event* event = new TransmissionEnd( getSimulation(), + "Transmission End", *peerDevice, PduPtr() ); + event->scheduleIn( link.delay_ ); + + statistics << count( "errors" ).scope( typeid(Medium) ); + } + } +} + +void Medium::collision() const +{ + statistics << count( "collisions" ).scope( typeid(Medium) ); +} + +void Medium::setErrorModel( ErrorModelPtr errorModel ) +{ + ODEMX_TRACE << log( "set error model" ) + .detail( "type", typeToString( typeid( *errorModel ) ) ) + .scope( typeid(Medium) ); + + defaultErrorModel_ = errorModel; +} + +bool Medium::addLink( const Device::AddressType& srcAddr, + const Device::AddressType& destAddr, base::SimTime delay, + bool duplex, ErrorModelPtr errorModel ) +{ + ODEMX_TRACE << log( "add link" ) + .detail( "from", srcAddr ) + .detail( "to", destAddr ) + .detail( "delay", delay ) + .detail( "error model", errorModel ? typeToString( typeid( *errorModel ) ) : "default" ) + .scope( typeid(Medium) ); + + Device* src = getDevice( srcAddr ); + Device* dest = getDevice( destAddr ); + + assert( src ); + assert( dest ); + + bool success = addLink( src, dest, delay, errorModel ); + if( duplex && success ) + { + return addLink( dest, src, delay, errorModel ); + } + return success; +} + +bool Medium::addLink( Device* src, Device* dest, base::SimTime delay, + ErrorModelPtr errorModel ) +{ + if( src == dest ) + { + warning << log( "Medium::addLink(): the given devices are the same" ) + .scope( typeid( Medium ) ); + return false; + } + + // overwrite existing entries + if( errorModel ) + { + topology_[ src ][ dest ] = LinkInfo( delay, errorModel ); + } + else + { + topology_[ src ][ dest ] = LinkInfo( delay, defaultErrorModel_ ); + } + return true; +} + +void Medium::removeLink( const Device::AddressType& srcAddr, + const Device::AddressType& destAddr, bool duplex ) +{ + ODEMX_TRACE << log( "remove link" ) + .detail( "from", srcAddr ) + .detail( "to", destAddr ) + .scope( typeid(Medium) ); + + Device* src = getDevice( srcAddr ); + Device* dest = getDevice( destAddr ); + + removeLink( src, dest ); + if( duplex ) + { + return removeLink( dest, src ); + } +} + +void Medium::removeLink( Device* src, Device* dest ) +{ + if( src == dest ) + { + warning << log( "Medium::removeLink(): the given devices are the same" ) + .scope( typeid( Medium ) ); + return; + } + + TopologyMap::iterator foundSrc = topology_.find( src ); + if( foundSrc != topology_.end() ) + { + LinkInfoMap& links = foundSrc->second; + LinkInfoMap::iterator foundDest = links.find( dest ); + if( foundDest != links.end() ) + { + // found link between both nodes, erase LinkInfo + links.erase( foundDest ); + } + } +} + +bool Medium::registerDevice( const Device::AddressType& address, Device& device ) +{ + device.setAddress( address ); + device.setMedium( *this ); + return devices_.insert( DeviceMap::value_type( address, &device ) ).second; +} + +Device* Medium::getDevice( const Device::AddressType& address ) const +{ + DeviceMap::const_iterator found = devices_.find( address ); + if( found != devices_.end() ) + { + return found->second; + } + + error << log( "Medium::getDevice(): no device registered" ) + .detail( "address", address ) + .scope( typeid(Medium) ); + return 0; +} + +const Medium::TopologyMap& Medium::getTopology() const +{ + return topology_; +} + +const Medium::DeviceMap& Medium::getDevices() const +{ + return devices_; +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/Sap.cpp b/odemx-lite/src/protocol/Sap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc1ba8384645e3112a1b39e81d04edabb26e7a6b --- /dev/null +++ b/odemx-lite/src/protocol/Sap.cpp @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Sap.cpp + * @author Ronald Kluth + * @date created at 2009/10/13 + * @brief Implementation of class odemx::protocol::Sap + * @sa Sap.h + * @since 3.0 + */ + +#include <odemx/protocol/Sap.h> +#include <odemx/protocol/ServiceProvider.h> + +namespace odemx { +namespace protocol { + +//------------------------------------------------------------buffer definitions + +Sap::BufferHead::BufferHead( base::Simulation& sim, const data::Label& label, Sap& sap ) +: synchronization::PortHeadT< PduPtr >( sim, label + " " + sap.getName() + " buffer", + synchronization::WAITING_MODE, 1000, 0 ) +, sap_( &sap ) +{} + +Sap& Sap::BufferHead::getSap() const +{ + return *sap_; +} + +Sap::BufferHead::Ptr Sap::BufferHead::create( base::Simulation& sim, + const data::Label& label, Sap& sap ) +{ + Ptr rv( new BufferHead( sim, label, sap ) ); + rv->initPort(); + return rv; +} + +//------------------------------------------------------construction/destruction + +Sap::Sap( base::Simulation& sim, const data::Label& label, const std::string& name ) +: name_( name ) +{ + queueHead_ = BufferHead::create( sim, label, *this ); + queueTail_ = queueHead_->getTail(); +} + +Sap::~Sap() +{ +} + +//-----------------------------------------------------------------public access + +const std::string& Sap::getName() const +{ + return name_; +} + +Sap::BufferHead* Sap::getBuffer() const +{ + return queueHead_.get(); +} + +void Sap::write( PduPtr p ) +{ + queueTail_->put( p ); +} + +PduPtr Sap::read() +{ + std::unique_ptr< PduPtr > p = queueHead_->get(); + if( ! p.get() ) + { + return PduPtr(); + } + return *p; +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/Service.cpp b/odemx-lite/src/protocol/Service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d50e88e6eb668fb789214620b11f4e154627d0d3 --- /dev/null +++ b/odemx-lite/src/protocol/Service.cpp @@ -0,0 +1,237 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Service.cpp + * @author Ronald Kluth + * @date created at 2009/10/12 + * @brief Implementation of class odemx::protocol::Service + * @sa Service.h + * @since 3.0 + */ + +#include <odemx/protocol/Service.h> +#include <odemx/protocol/ErrorModel.h> +#include <odemx/protocol/Layer.h> +#include <odemx/util/DeletePtr.h> + +namespace odemx { +namespace protocol { + +//------------------------------------------------------static member definition + +Service::AddressMap Service::services_; +std::shared_ptr< ErrorModel > Service::errorModel_; + +//------------------------------------------------------construction/destruction + +Service::Service( base::Simulation& sim, const data::Label& label ) +: ServiceProvider( sim, label ) +, receiveSap_( 0 ) +{ + receiveSap_ = addSap( "odemx_internal_service_receive_SAP" ); + assert( receiveSap_ ); +} + +Service::~Service() +{ + std::for_each( outputSaps_.begin(), outputSaps_.end(), DeletePtr< Sap >() ); +} + +//-------------------------------------------------------------user registration + +bool Service::registerService( const AddressType& address, Service& service ) +{ + service.setAddress( address ); + return services_.insert( AddressMap::value_type( address, &service ) ).second; +} + +bool Service::removeService( const AddressType& address ) +{ + AddressMap::iterator found = services_.find( address ); + if( found != services_.end() ) + { + found->second->address_.clear(); + services_.erase( found ); + return true; + } + return false; +} + +const Service::AddressMap& Service::getAddressMap() +{ + return services_; +} + +const Service::AddressType& Service::getAddress() const +{ + return address_; +} + +void Service::setAddress( const AddressType& addr ) +{ + ODEMX_TRACE << log( "set address" ) + .detail( "value", addr ) + .scope( typeid(Service) ); + + address_ = addr; +} + +//--------------------------------------------------------service implementation + +Service* Service::getPeer( const AddressType& peer ) +{ + AddressMap::const_iterator found = services_.find( peer ); + if( found != services_.end() ) + { + return found->second; + } + return 0; +} + +bool Service::send( const AddressType& peerAddress, PduPtr p ) const +{ + Service* peer = getPeer( peerAddress ); + if( peer != 0 ) + { + ODEMX_TRACE << log( "send" ) + .detail( "peer", peerAddress ) + .scope( typeid(Service) ); + + peer->receive( p ); + return true; + } + else + { + warning << log( "Service::send(): peer not registered" ) + .detail( "address", peerAddress ) + .scope( typeid(Service) ); + } + return false; +} + +bool Service::pass( const std::string& sapName, PduPtr p ) +{ + Sap* sap = 0; + if( layer_ ) + { + sap = layer_->getUpperLayer()->getSap( sapName ); + } + else + { + sap = getReceiveSap( sapName ); + } + + if( sap ) + { + ODEMX_TRACE << log( "pass" ) + .detail( "SAP", sapName ) + .scope( typeid(Service) ); + + sap->write( p ); + return true; + } + else + { + warning << log( "Service::pass(): output SAP not found" ) + .detail( "name", sapName ) + .scope( typeid(Service) ); + } + return false; +} + +Sap* Service::addReceiveSap( const std::string& name ) +{ + SapVec::iterator found = std::find_if( + outputSaps_.begin(), outputSaps_.end(), Sap::MatchName( name ) ); + + if( found != outputSaps_.end() ) + { + warning << log( "Service::addReceiveSap(): SAP already exists" ) + .detail( "name", name ) + .scope( typeid(Service) ); + return *found; + } + + ODEMX_TRACE << log( "add receive SAP" ) + .detail( "name", name ) + .scope( typeid(Service) ); + + Sap* sap = new Sap( getSimulation(), getLabel(), name ); + outputSaps_.push_back( sap ); + return sap; +} + +Sap* Service::getReceiveSap( const std::string& name ) +{ + SapVec::iterator found = std::find_if( + outputSaps_.begin(), outputSaps_.end(), Sap::MatchName( name ) ); + + if( found != outputSaps_.end() ) + { + return *found; + } + return 0; +} + +void Service::receive( PduPtr p ) +{ + bool pass = true; + + if( errorModel_ ) + { + pass = errorModel_->apply( p ); + } + + if( pass ) + { + ODEMX_TRACE << log( "receive success" ).scope( typeid(Service) ); + + receiveSap_->write( p ); + } + else + { + ODEMX_TRACE << log( "receive failure" ).scope( typeid(Service) ); + } +} + +void Service::setErrorModel( std::shared_ptr< ErrorModel > em ) +{ + errorModel_ = em; +} + +//------------------------------------------------------------process life cycle + +void Service::handleInput( const std::string& sap, PduPtr pdu ) +{ + if( sap == receiveSap_->getName() ) + { + ODEMX_TRACE << log( "handle receive" ).scope( typeid(Service) ); + + handleReceive( pdu ); + } + else + { + ODEMX_TRACE << log( "handle send" ).detail( "input SAP", sap ) + .scope( typeid(Service) ); + + handleSend( sap, pdu ); + } +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/protocol/ServiceProvider.cpp b/odemx-lite/src/protocol/ServiceProvider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70ab8d7411bc251ba96e6434cb52b4c06e77f0b4 --- /dev/null +++ b/odemx-lite/src/protocol/ServiceProvider.cpp @@ -0,0 +1,177 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ServiceProvider.cpp + * @author Ronald Kluth + * @date created at 2009/10/29 + * @brief Implementation of class odemx::protocol::ServiceProvider + * @sa ServiceProvider.h + * @since 3.0 + */ + +#include <odemx/protocol/ServiceProvider.h> +#include <odemx/protocol/Layer.h> +#include <odemx/protocol/Sap.h> +#include <odemx/util/DeletePtr.h> + +#include <algorithm> // for_each, find_if + +namespace odemx { +namespace protocol { + +//------------------------------------------------------construction/destruction + +ServiceProvider::ServiceProvider( base::Simulation& sim, const data::Label& label ) +: base::Process( sim, label ) +, layer_( 0 ) +, saps_() +{ + ODEMX_TRACE << log( "create" ).scope( typeid(ServiceProvider) ); + this->activate(); +} + +ServiceProvider::~ServiceProvider() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(ServiceProvider) ); + + std::for_each( saps_.begin(), saps_.end(), DeletePtr< Sap >() ); +} + +//------------------------------------------------------------process life cycle + +int ServiceProvider::main() +{ + while( true ) + { + if( sapQueues_.empty() ) + { + error << log( "ServiceProvider::main(): " + "no SAPs registered, cannot enter wait state" ) + .scope( typeid(ServiceProvider) ); + return -1; + } + + synchronization::IMemory* alerter = base::Process::wait( &sapQueues_ ); + if( alerter != 0 ) + { + Sap::BufferHead* sapQ = static_cast< Sap::BufferHead* >( alerter ); + const std::string& sapName = sapQ->getSap().getName(); + + ODEMX_TRACE << log( "handle input" ) + .detail( "SAP", sapName ) + .scope( typeid(ServiceProvider) ); + + handleInput( sapName, sapQ->getSap().read() ); + } + else + { + error << log( "ServiceProvider::main(): alerter is 0" ) + .scope( typeid(ServiceProvider) ); + } + } + return 0; +} + +//-----------------------------------------------------------------member access + +void ServiceProvider::setLayer( Layer* layer ) +{ + assert( layer ); + + ODEMX_TRACE << log( "set layer" ) + .detail( "label", layer->getLabel() ) + .scope( typeid(ServiceProvider) ); + + layer_ = layer; +} + +Layer* ServiceProvider::getLayer() const +{ + return layer_; +} + +Sap* ServiceProvider::addSap( const std::string& name ) +{ + SapVec::iterator found = std::find_if( + saps_.begin(), saps_.end(), Sap::MatchName( name ) ); + + if( found != saps_.end() ) + { + warning << log( "ServiceProvider::addSap(): SAP already exists" ) + .detail( "name", name ) + .scope( typeid(ServiceProvider) ); + return *found; + } + + ODEMX_TRACE << log( "add SAP" ) + .detail( "name", name ) + .scope( typeid(ServiceProvider) ); + + Sap* sap = new Sap( getSimulation(), getLabel(), name ); + saps_.push_back( sap ); + sapQueues_.push_back( sap->getBuffer() ); + + if( layer_ ) + { + layer_->addSap( sap ); + } + return sap; +} + +bool ServiceProvider::removeSap( const std::string& name ) +{ + SapVec::iterator found = std::find_if( + saps_.begin(), saps_.end(), Sap::MatchName( name ) ); + + if( found != saps_.end() ) + { + ODEMX_TRACE << log( "remove SAP" ) + .detail( "name", name ) + .scope( typeid(ServiceProvider) ); + + if( layer_ ) + { + layer_->removeSap( name ); + } + + delete *found; + saps_.erase( found ); + return true; + } + return false; +} + +Sap* ServiceProvider::getSap( const std::string& name ) const +{ + SapVec::const_iterator found = std::find_if( + saps_.begin(), saps_.end(), Sap::MatchName( name ) ); + + if( found != saps_.end() ) + { + return *found; + } + return 0; +} + +const ServiceProvider::SapVec& ServiceProvider::getSaps() const +{ + return saps_; +} + +} } // namespace odemx protocol diff --git a/odemx-lite/src/protocol/Stack.cpp b/odemx-lite/src/protocol/Stack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95af4014b2032047d192c5cc1e6b903d576c297c --- /dev/null +++ b/odemx-lite/src/protocol/Stack.cpp @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Stack.cpp + * @author Ronald Kluth + * @date created at 2009/10/16 + * @brief Implementation of class odemx::protocol::Stack + * @sa Stack.h + * @since 3.0 + */ + +#include <odemx/protocol/Stack.h> +#include <odemx/protocol/Sap.h> +#include <odemx/protocol/Layer.h> +#include <odemx/util/DeletePtr.h> + +namespace odemx { +namespace protocol { + +Stack::Stack( base::Simulation& sim, const data::Label& label ) +: data::Producer( sim, label ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Stack) ); + + layers_.push_back( new Layer( sim, label + " internal top layer" ) ); +} + +Stack::~Stack() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Stack) ); + + // delete SAPs held by top layer + // (the layer only deletes its service providers) + Layer::SapMap& saps = layers_.front()->getSaps(); + for( Layer::SapMap::iterator iter = saps.begin(); iter != saps.end(); ++iter ) + { + delete iter->second; + } + + // delete all layers + std::for_each( layers_.begin(), layers_.end(), DeletePtr< Layer >() ); +} + +Sap* Stack::getSap( const std::string& name ) const +{ + if( layers_.size() > 1 ) + { + Sap* sap = layers_[ 1 ]->getSap( name ); + if( sap ) + { + return sap; + } + else + { + error << log( "Stack::getSap(): SAP not found in top layer" ) + .detail( "name", name ) + .scope( typeid(Stack) ); + } + } + else + { + error << log( "Stack::getSap():" + "no service providing layer, cannot access SAP" ) + .detail( "name", name ) + .scope( typeid(Stack) ); + } + return 0; +} + +void Stack::addLayer( Layer* layer ) +{ + ODEMX_TRACE << log( "add layer" ) + .detail( "label", layer->getLabel() ) + .scope( typeid(Stack) ); + + layers_.back()->setLowerLayer( layer ); + layer->setUpperLayer( layers_.back() ); + layers_.push_back( layer ); +} + +Sap* Stack::addReceiveSap( const std::string& name ) +{ + Layer* topLayer = layers_.front(); + Sap* sap = topLayer->getSap( name ); + + if( sap ) + { + warning << log( "Stack::addReceiveSap(): SAP already exists" ) + .detail( "name", name ) + .scope( typeid(Stack) ); + } + else + { + ODEMX_TRACE << log( "add receive SAP" ) + .detail( "name", name ) + .scope( typeid(Stack) ); + + sap = new Sap( getSimulation(), getLabel(), name ); + topLayer->addSap( sap ); + } + return sap; +} + +Sap* Stack::getReceiveSap( const std::string& name ) const +{ + return layers_.front()->getSap( name ); +} + +const Stack::LayerVec& Stack::getLayers() const +{ + return layers_; +} + +} } // namespace odemx::protocol diff --git a/odemx-lite/src/random/ContinuousConst.cpp b/odemx-lite/src/random/ContinuousConst.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cff2ce94010e8c96e2f3821aebb3822104a257d --- /dev/null +++ b/odemx-lite/src/random/ContinuousConst.cpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file ContinuousConst.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::ContinuousConst + */ + +#include <odemx/random/ContinuousConst.h> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +ContinuousConst::ContinuousConst( base::Simulation& sim, const data::Label& label, + double value ) +: ContinuousDist( sim, label ) +, value_( value ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(ContinuousConst) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(ContinuousConst) ); + statistics << param( "value", value_ ).scope( typeid(ContinuousConst) ); +} + +ContinuousConst::~ContinuousConst() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(ContinuousConst) ); +} + +//------------------------------------------------------------------------sample + +double ContinuousConst::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(ContinuousConst) ); + + statistics << count( "uses" ).scope( typeid(ContinuousConst) ); + + return value_; +} + +//-----------------------------------------------------------------------getters + +double ContinuousConst::getValue() +{ + return value_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/ContinuousDist.cpp b/odemx-lite/src/random/ContinuousDist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..09c1e2defc396676f387de02ee5969a901cf57fc --- /dev/null +++ b/odemx-lite/src/random/ContinuousDist.cpp @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file ContinuousDist.cpp + + \author Ralf Gerstenberger + + \date created at 2003/05/09 + + \brief Implementation of odemx::random::ContinuousDist + + \sa ContinuousDist.h + + \since 1.0 +*/ + +#include <odemx/random/ContinuousDist.h> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +ContinuousDist::ContinuousDist( base::Simulation& sim, const data::Label& label ) +: Dist( sim, label ) +{ +} + +ContinuousDist::~ContinuousDist() +{ +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/DiscreteConst.cpp b/odemx-lite/src/random/DiscreteConst.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbe1bc64b9c185f6c739d3eb15155dc4aa8773e6 --- /dev/null +++ b/odemx-lite/src/random/DiscreteConst.cpp @@ -0,0 +1,67 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file DiscreteConst.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::DiscreteConst + */ + +#include <odemx/random/DiscreteConst.h> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +DiscreteConst::DiscreteConst( base::Simulation& sim, const data::Label& label, int value ) +: DiscreteDist( sim, label ), + value_( value ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(DiscreteConst) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(DiscreteConst) ); + statistics << param( "value", value_ ).scope( typeid(DiscreteConst) ); +} + +DiscreteConst::~DiscreteConst() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(DiscreteConst) ); +} + +//------------------------------------------------------------------------sample + +int DiscreteConst::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(DiscreteConst) ); + + statistics << count( "uses" ).scope( typeid(DiscreteConst) ); + + return value_; +} + +//-----------------------------------------------------------------------getters + +int DiscreteConst::getValue() +{ + return value_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/DiscreteDist.cpp b/odemx-lite/src/random/DiscreteDist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad00dd483948400cd0cda04552f99bb581f658cc --- /dev/null +++ b/odemx-lite/src/random/DiscreteDist.cpp @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file DiscreteDist.cpp + + \author Ralf Gerstenberger + + \date created at 2003/05/09 + + \brief Implementation of odemx::random::DiscreteDist + + \sa DiscreteDist.h + + \since 1.0 +*/ + +#include <odemx/random/DiscreteDist.h> + +namespace odemx { +namespace random { + +DiscreteDist::DiscreteDist( base::Simulation& sim, const data::Label& label ) +: Dist( sim, label ) +{ +} + +DiscreteDist::~DiscreteDist() +{ +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/Dist.cpp b/odemx-lite/src/random/Dist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e6ca330e54b45664329cbb7048d6ae53e3974e2 --- /dev/null +++ b/odemx-lite/src/random/Dist.cpp @@ -0,0 +1,108 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Dist.cpp + + \author Ralf Gerstenberger + + \date created at 2003/05/09 + + \brief Implementation of odemx::random::Dist + + \sa Dist.h + + \since 1.0 +*/ + +#include <odemx/random/Dist.h> +#include <odemx/random/DistContext.h> +#include <odemx/base/Simulation.h> + +namespace odemx { +namespace random { + +Dist::Dist( base::Simulation& sim, const data::Label& label ) +: Producer( sim, label ) +, context( sim ) +, u( 0 ) +, ustart( 0 ) +, antithetics( 0 ) +{ + u = ustart = context.getNextSeed(); +} + +Dist::~Dist() +{ +} + +void Dist::setSeed( int n ) +{ + if( n < 0 ) + { + n= -n; + } + if( n >= (int)zyqmodulo ) + { + n = n - ( (int)( n / zyqmodulo ) ) * zyqmodulo; + } + if( n == 0 ) + { + n = (int)( zyqmodulo / 2 ); + } + u = ustart = n; +} + +unsigned long Dist::getSeed() +{ + return ustart; +} + +double Dist::getSample() +{ + int k; + + k = 32; + u = k * u; + if( u >= zyqmodulo ) + { + u = u- ((int)( u / zyqmodulo ) ) * zyqmodulo; + } + + // yes, this is needed twice + k = 32; + u = k * u; + if( u >= zyqmodulo ) + { + u = u- ((int)( u / zyqmodulo ) ) * zyqmodulo; + } + + k = 8; + u = k * u; + if( u >= zyqmodulo ) + { + u = u- ((int)( u / zyqmodulo ) ) * zyqmodulo; + } + + double help = (double)u / (double)zyqmodulo; + + double zyqSample = antithetics ? 1.0 - help : help; + + return zyqSample; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/DistContext.cpp b/odemx-lite/src/random/DistContext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2af6f584df75d859791bcaccb70c6bee553eb1c4 --- /dev/null +++ b/odemx-lite/src/random/DistContext.cpp @@ -0,0 +1,107 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file DistContext.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::DistContext + */ + +#include <odemx/random/DistContext.h> + +namespace odemx { +namespace random { + +const unsigned long zyqmodulo = 67099547; + +DistContext::DistContext() +: zyqSeed_( 907 ) +{ +} + +DistContext::~DistContext() +{ +} + +void DistContext::setSeed( int n ) +{ + if( n < 0 ) + { + n = -n; + } + + if( n >= (int)zyqmodulo ) + { + n = n - ( (int)(n / zyqmodulo) ) * zyqmodulo; + } + + if( n == 0 ) + { + n = (int)( zyqmodulo / 2 ); + } + + zyqSeed_ = n; +} + +unsigned long DistContext::getSeed() +{ + return zyqSeed_; +} + +unsigned long DistContext::getNextSeed() +{ + computeNextSeed(); + return zyqSeed_; +} + +void DistContext::computeNextSeed() +{ + int k; + + k = 7; + zyqSeed_ = zyqSeed_ * k; + if( zyqSeed_ >= zyqmodulo ) + { + zyqSeed_ = zyqSeed_ - ( (int)( zyqSeed_ / zyqmodulo ) ) * zyqmodulo; + } + + k = 13; + zyqSeed_ = zyqSeed_ * k; + if( zyqSeed_ >= zyqmodulo ) + { + zyqSeed_ = zyqSeed_ - ( (int)( zyqSeed_ / zyqmodulo ) ) * zyqmodulo; + } + + k = 15; + zyqSeed_ = zyqSeed_ * k; + if( zyqSeed_ >= zyqmodulo ) + { + zyqSeed_ = zyqSeed_ - ( (int)( zyqSeed_ / zyqmodulo ) ) * zyqmodulo; + } + + k = 27; + zyqSeed_ = zyqSeed_ * k; + if( zyqSeed_ >= zyqmodulo ) + { + zyqSeed_ = zyqSeed_ - ( (int)( zyqSeed_ / zyqmodulo ) ) * zyqmodulo; + } +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/Draw.cpp b/odemx-lite/src/random/Draw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74865fdc25cf2dcc060ed9095c00880b96b042c1 --- /dev/null +++ b/odemx-lite/src/random/Draw.cpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Draw.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::Draw + */ + +#include <odemx/random/Draw.h> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +Draw::Draw( base::Simulation& sim, const data::Label& label, double probability ) +: DiscreteDist( sim, label ) +{ + probability_ = probability; + + ODEMX_TRACE << log( "create" ).scope( typeid(Draw) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(Draw) ); + statistics << param( "probability", probability_ ).scope( typeid(Draw) ); +} + +Draw::~Draw() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Draw) ); +} + +//------------------------------------------------------------------------sample + +int Draw::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(Draw) ); + + statistics << count( "uses" ).scope( typeid(Draw) ); + + return ( probability_ > Dist::getSample() ? 1 : 0 ); +} + +//-----------------------------------------------------------------------getters + +double Draw::getProbability() +{ + return probability_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/Erlang.cpp b/odemx-lite/src/random/Erlang.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7d368e9c0705f929a5086cba452ce728768fb25 --- /dev/null +++ b/odemx-lite/src/random/Erlang.cpp @@ -0,0 +1,95 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Erlang.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::Erlang + */ + +#include <odemx/random/Erlang.h> + +#include <cmath> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +Erlang::Erlang( base::Simulation& sim, const data::Label& label, double rate, int shape ) +: ContinuousDist( sim, label ) +{ + if( rate <= 0.0 ) + { + rate = ( rate < 0.0 ) ? -rate : 0.01; + warning << log( "Erlang(): rate <= 0.0; -rate or 0.01 used" ) + .scope( typeid(Erlang) ); + } + + if( shape <= 0 ) + { + shape = ( shape < 0 ) ? -shape : 1; + warning << log( "Erlang(): shape <= 0; -shape or 1 used" ) + .scope( typeid(Erlang) ); + } + rate_ = rate; + shape_ = shape; + + ODEMX_TRACE << log( "create" ).scope( typeid(Erlang) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(Erlang) ); + statistics << param( "rate", rate_ ).scope( typeid(Erlang) ); + statistics << param( "shape", shape_ ).scope( typeid(Erlang) ); +} + +Erlang::~Erlang() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Erlang) ); +} + +//------------------------------------------------------------------------sample + +double Erlang::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(Erlang) ); + + statistics << count( "uses" ).scope( typeid(Erlang) ); + + double erlangTmp = 0.0; + for( int i = 0; i < shape_; ++i ) + { + erlangTmp += -( 1 / rate_ ) * std::log( Dist::getSample() ); + } + return erlangTmp; +} + +//-----------------------------------------------------------------------getters + +double Erlang::getRate() +{ + return rate_; +} + +int Erlang::getShape() +{ + return shape_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/NegativeExponential.cpp b/odemx-lite/src/random/NegativeExponential.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a718d701768bfab7aca3465da039a585652142e --- /dev/null +++ b/odemx-lite/src/random/NegativeExponential.cpp @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file NegativeExponential.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::NegativeExponential + */ + +#include <odemx/random/NegativeExponential.h> + +#include <cmath> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +NegativeExponential::NegativeExponential( base::Simulation& sim, const data::Label& label, + double inverseMean ) +: ContinuousDist( sim, label ) +{ + if( inverseMean <= 0.0 ) + { + inverseMean = ( inverseMean < 0.0 ) ? -inverseMean : 0.001; + + warning << log( "NegativeExponential(): inverseMean <= 0; -inverseMean or 0.001 used") + .scope( typeid(NegativeExponential) ); + } + inverseMean_ = inverseMean; + + ODEMX_TRACE << log( "create" ).scope( typeid(NegativeExponential) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(NegativeExponential) ); + statistics << param( "inverse mean", inverseMean_ ).scope( typeid(NegativeExponential) ); +} + +NegativeExponential::~NegativeExponential() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(NegativeExponential) ); +} + +//------------------------------------------------------------------------sample + +double NegativeExponential::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(NegativeExponential) ); + + statistics << count( "uses" ).scope( typeid(NegativeExponential) ); + + return ( -std::log( Dist::getSample() ) / inverseMean_ ); +} + +//-----------------------------------------------------------------------getters + +double NegativeExponential::getInverseMean() +{ + return inverseMean_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/Normal.cpp b/odemx-lite/src/random/Normal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4140dfff90a84c4d1a570844c61d31756cded026 --- /dev/null +++ b/odemx-lite/src/random/Normal.cpp @@ -0,0 +1,101 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Normal.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::Normal + */ + +#include <odemx/random/Normal.h> + +#include <cmath> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +Normal::Normal( base::Simulation& sim, const data::Label& label, double mean, + double deviation ) +: ContinuousDist( sim, label ) +{ + if( deviation < 0.0 ) + { + deviation = -deviation; + + warning << log( "Normal(): given deviation < 0; changed to -deviation" ) + .scope( typeid(Normal) ); + } + + mean_ = mean; + deviation_ = deviation; + zyqeven = false; + zyqu = zyqv = 0.0; + + ODEMX_TRACE << log( "create" ).scope( typeid(Normal) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(Normal) ); + statistics << param( "mean", mean_ ).scope( typeid(Normal) ); + statistics << param( "deviation", deviation_ ).scope( typeid(Normal) ); +} + +Normal::~Normal() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Normal) ); +} + +//------------------------------------------------------------------------sample + +double Normal::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(Normal) ); + + statistics << count( "uses" ).scope( typeid(Normal) ); + + double z; + if( zyqeven ) + { + zyqeven = false; + z = zyqu * std::cos( zyqv ); + } + else + { + zyqeven = true; + zyqu = std::sqrt( -2.0 * std::log( Dist::getSample() ) ); + zyqv = 6.28318530717958647693 * Dist::getSample(); + z = zyqu * std::sin( zyqv ); + }; + return ( z * deviation_ + mean_ ); +}; + +//-----------------------------------------------------------------------getters + +double Normal::getMean() +{ + return mean_; +} + +double Normal::getDeviation() +{ + return deviation_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/Poisson.cpp b/odemx-lite/src/random/Poisson.cpp new file mode 100644 index 0000000000000000000000000000000000000000..683cb8dc7015140394f422b883053e5d8b4ef73d --- /dev/null +++ b/odemx-lite/src/random/Poisson.cpp @@ -0,0 +1,90 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Poisson.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::Poisson + */ + +#include <odemx/random/Poisson.h> + +#include <cmath> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +Poisson::Poisson( base::Simulation& sim, const data::Label& label, double mean ) +: DiscreteDist( sim, label ) +{ + if( mean <= 0.0 ) + { + mean = ( mean < 0.0 ) ? -mean : 0.0010; + warning << log( "Poisson(): mean value is <= 0.0; changed to -mean" ) + .scope( typeid(Poisson) ); + } + mean_ = mean; + + ODEMX_TRACE << log( "create" ).scope( typeid(Poisson) ); + + statistics << param( "seed", Dist::getSeed() ).scope(typeid(Poisson) ); + statistics << param( "mean", mean_ ).scope(typeid(Poisson) ); +} + +Poisson::~Poisson() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Poisson) ); +} + +//------------------------------------------------------------------------sample + +int Poisson::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(Poisson) ); + + statistics << count( "uses" ).scope( typeid(Poisson) ); + + double q; + double r; + int m = 0; + + r = std::exp( -mean_ ); + q = 1.0; + + while( q >= r ) + { + q *= Dist::getSample(); + m += 1; + }; + + m -= 1; + return m; +} + +//-----------------------------------------------------------------------getters + +double Poisson::getMean() +{ + return mean_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/RandomInt.cpp b/odemx-lite/src/random/RandomInt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0e3e333a900b4b585a8008f0198da4e14bd8338 --- /dev/null +++ b/odemx-lite/src/random/RandomInt.cpp @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file RandomInt.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::RandomInt + */ + +#include <odemx/random/RandomInt.h> + +#include <algorithm> +#include <cmath> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +RandomInt::RandomInt( base::Simulation& sim, const data::Label& label, int lowerBound, + int upperBound ) +: DiscreteDist( sim, label ) +{ + if( lowerBound > upperBound ) + { + std::swap( lowerBound, upperBound ); + warning << log( "RandomInt(): lower bound greater than upper bound; bounds swapped" ) + .scope( typeid(RandomInt) ); + } + + lowerBound_ = lowerBound; + upperBound_ = upperBound; + zyqSpan_ = upperBound_ - lowerBound_; + + ODEMX_TRACE << log( "create" ).scope( typeid(RandomInt) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(RandomInt) ); + statistics << param( "lower bound", lowerBound_ ).scope( typeid(RandomInt) ); + statistics << param( "upper bound", upperBound_ ).scope( typeid(RandomInt) ); +} + +RandomInt::~RandomInt() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(RandomInt) ); +} + +//------------------------------------------------------------------------sample + +int RandomInt::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(RandomInt) ); + + statistics << count( "uses" ).scope( typeid(RandomInt) ); + + return (int)std::floor( zyqSpan_ * DiscreteDist::getSample() ) + lowerBound_; +} + +//-----------------------------------------------------------------------getters + +int RandomInt::getLowerBound() +{ + return lowerBound_; +} + +int RandomInt::getUpperBound() +{ + return upperBound_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/random/Uniform.cpp b/odemx-lite/src/random/Uniform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ccc140f057c80b3e8094807985f9c2a2aa4b444 --- /dev/null +++ b/odemx-lite/src/random/Uniform.cpp @@ -0,0 +1,85 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- + +/** + * @file Uniform.cpp + * @date Feb 22, 2009 + * @author Ronald Kluth + * @brief Implementation of odemx::random::Uniform + */ + +#include <odemx/random/Uniform.h> + +#include <algorithm> + +namespace odemx { +namespace random { + +//------------------------------------------------------construction/destruction + +Uniform::Uniform( base::Simulation& sim, const data::Label& label, double lowerBound, + double upperBound ) +: ContinuousDist( sim, label ) +{ + if( lowerBound > upperBound ) + { + std::swap( lowerBound, upperBound ); + warning << log( "Uniform(): lower bound greater than upper bound; bounds swapped" ) + .scope( typeid(Uniform) ); + } + lowerBound_ = lowerBound; + upperBound_ = upperBound; + zyqSpan_ = upperBound_ - lowerBound_; + + ODEMX_TRACE << log( "create" ).scope( typeid(Uniform) ); + + statistics << param( "seed", Dist::getSeed() ).scope( typeid(Uniform) ); + statistics << param( "lower bound", lowerBound_ ).scope( typeid(Uniform) ); + statistics << param( "upper bound", upperBound_ ).scope( typeid(Uniform) ); +} + +Uniform::~Uniform() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Uniform) ); +} + +//------------------------------------------------------------------------sample + +double Uniform::sample() +{ + ODEMX_TRACE << log( "sample" ).scope( typeid(Uniform) ); + + statistics << count( "uses" ).scope( typeid(Uniform) ); + + return ( zyqSpan_ * getSample() + lowerBound_ ); +} + +//-----------------------------------------------------------------------getters + +double Uniform::getLowerBound() +{ + return lowerBound_; +} + +double Uniform::getUpperBound() +{ + return upperBound_; +} + +} } // namespace odemx::random diff --git a/odemx-lite/src/statistics/Accumulate.cpp b/odemx-lite/src/statistics/Accumulate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f59ed7572ed8e62a5d30864a15f21ac7874cabd --- /dev/null +++ b/odemx-lite/src/statistics/Accumulate.cpp @@ -0,0 +1,224 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Accumulate.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Accumulate + * @sa Accumulate.h + * @since 3.0 + */ + +#include <odemx/statistics/Accumulate.h> +#include <odemx/data/ReportTable.h> +#include <odemx/data/Report.h> + +#include <cmath> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Accumulate::Accumulate( base::Simulation& sim, const data::Label& label, Approx app ) +: Tab( sim, label ) +, approximation_( app ) +, startTime_( 0 ) +, lastTime_( 0 ) +, lastValue_( 0 ) +, zeros_( 0 ) +, minValue_( 0.0 ) +, maxValue_( 0.0 ) +, sum_( 0.0 ) +, sumSq_( 0.0 ) +, sumWeight_( 0.0 ) +, sumSqWeight_( 0.0 ) +{ +} + +Accumulate::~Accumulate() +{ +} + +//---------------------------------------------------------------------modifiers + +void Accumulate::update( base::SimTime time, double value ) +{ + // set start time for later computation of time span + if( getUpdateCount() == 0 ) + { + startTime_ = time; + } + + // update usage counter + Tab::update(); + + // update non-weighted sums + sum_ += value; + sumSq_ += std::pow( value, 2 ); + + // compute time span since last update and save current time + base::SimTime lastSpan = time - lastTime_; + lastTime_ = time; + + // compute weighted sums according to the approximation mode + if( getUpdateCount() > 1 ) + { + if( approximation_ == linear ) + { + double mean = ( value + lastValue_ ) / 2; + sumWeight_ += mean * lastSpan; + sumSqWeight_ += std::pow( mean, 2 ) * lastSpan; + } + else // approximation_ == stepwise + { + sumWeight_ += lastValue_ * lastSpan; + sumSqWeight_ += lastValue_ * lastValue_ * lastSpan; + } + } + + // remember the current update value + lastValue_ = value; + + // update min and max values + if( Tab::getUpdateCount() == 1 ) + { + minValue_ = maxValue_ = value; + } + else if( value < minValue_ ) + { + minValue_ = value; + } + else if( value > maxValue_ ) + { + maxValue_ = value; + } + + if( value == 0 ) + { + ++zeros_; + } +} + +void Accumulate::reset( base::SimTime time ) +{ + Tab::reset( time ); + + zeros_ = 0; + minValue_ = maxValue_ = sum_ = sumSq_ = sumWeight_ = sumSqWeight_ = lastValue_ = 0.0; + + startTime_ = lastTime_ = time; +} + +//-----------------------------------------------------------------------getters + +std::size_t Accumulate::getZeros() const +{ + return zeros_; +} + +double Accumulate::getMin() const +{ + return minValue_; +} + +double Accumulate::getMax() const +{ + return maxValue_; +} + +double Accumulate::getMean() const +{ + return getUpdateCount() > 0 ? sum_ / getUpdateCount() : 0.0; +} + +double Accumulate::getWeightedMean() const +{ + base::SimTime span = lastTime_ - startTime_; + + // does not consider the last time span till this call, + // call update once more before getting the mean value ?!? + if( span == 0 ) + { + return 0.0; + } + + return sumWeight_ / span; +} + +double Accumulate::getStandardDeviation() const +{ + if( getUpdateCount() <= 1 ) + { + return 0.0; + } + + double mean = getMean(); + double variance = std::fabs( sumSq_ / getUpdateCount() - std::pow( mean, 2 ) ); + return std::sqrt( variance ); +} + +double Accumulate::getWeightedStandardDeviation() const +{ + if( getUpdateCount() <= 1 ) + { + return 0.0; + } + + base::SimTime span = lastTime_ - startTime_; + + if( span == 0 ) + { + return 0.0; + } + + double weightedMean = getWeightedMean(); + double variance = std::fabs( sumSqWeight_ / span - std::pow( weightedMean, 2 ) ); + return std::sqrt( variance ); +} + +//------------------------------------------------------------------------report + +void Accumulate::report( data::Report& report ) +{ + using namespace data; + ReportTable::Definition def; + def.addColumn( "Name", ReportTable::Column::STRING ); + def.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + def.addColumn( "Uses", ReportTable::Column::INTEGER ); + def.addColumn( "Min", ReportTable::Column::REAL ); + def.addColumn( "Max", ReportTable::Column::REAL ); + def.addColumn( "Mean", ReportTable::Column::REAL ); + def.addColumn( "Weighted Mean", ReportTable::Column::REAL ); + def.addColumn( "Std Deviation", ReportTable::Column::REAL ); + def.addColumn( "Weighted StDev", ReportTable::Column::REAL ); + ReportTable& table = report.getTable( "Accumulate Statistics", def ); + table + << getLabel() + << getResetTime() + << getUpdateCount() + << getMin() + << getMax() + << getMean() + << getWeightedMean() + << getStandardDeviation() + << getWeightedStandardDeviation(); +} + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/statistics/Count.cpp b/odemx-lite/src/statistics/Count.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e108087a7fb53cb2e242ae94d233ca2a863073a --- /dev/null +++ b/odemx-lite/src/statistics/Count.cpp @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Count.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Count + * @sa Count.h + * @since 3.0 + */ + +#include <odemx/statistics/Count.h> +#include <odemx/data/ReportTable.h> +#include <odemx/data/Report.h> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Count::Count( base::Simulation& sim, const data::Label& label ) +: Tab( sim, label ) +, count_( 0 ) +{ +} + +Count::~Count() +{ +} + +//---------------------------------------------------------------------modifiers + +void Count::update( int value ) +{ + Tab::update(); + count_ += value; +} + +void Count::reset( base::SimTime time ) +{ + Tab::reset( time ); + count_ = 0; +} + +//-----------------------------------------------------------------------getters + +int Count::getValue() const +{ + return count_; +} + +//------------------------------------------------------------------------report + +void Count::report( data::Report& report ) +{ + using namespace data; + + ReportTable::Definition def; + def.addColumn( "Name", ReportTable::Column::STRING ); + def.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + def.addColumn( "Uses", ReportTable::Column::INTEGER ); + def.addColumn( "Value", ReportTable::Column::INTEGER ); + ReportTable& table = report.getTable( "Count Statistics", def ); + table + << getLabel() + << getResetTime() + << getUpdateCount() + << getValue(); +} + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/statistics/Histogram.cpp b/odemx-lite/src/statistics/Histogram.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c74eca16c9d651e2a331c47fad9e350ead03b4f --- /dev/null +++ b/odemx-lite/src/statistics/Histogram.cpp @@ -0,0 +1,215 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Histogram.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Histogram + * @sa Histogram.h + * @since 3.0 + */ + +#include <odemx/statistics/Histogram.h> +#include <odemx/data/Report.h> + +#include <cmath> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Histogram::Histogram( base::Simulation& sim, const data::Label& label, + double lowerBound, double upperBound, unsigned int cellCount ) +: Tally( sim, label ) +, lowerBound_( lowerBound ) +, upperBound_( upperBound ) +, cellCount_( cellCount + 2 ) +{ + if( upperBound_ == lowerBound_ ) + { + upperBound_ = lowerBound_ + 100.0; + } + + if( upperBound_ < lowerBound_ ) + { + std::swap( lowerBound_, upperBound_ ); + } + + cellWidth_ = ( upperBound_ - lowerBound_ ) / ( cellCount_ - 2 ); + + cellData_.resize( cellCount_, Cell() ); + maxCellIndex_ = cellData_.size() - 1; +} + +Histogram::~Histogram() +{ +} + +//---------------------------------------------------------------------modifiers + +void Histogram::update( double value ) +{ + Tally::update( value ); + + // the vector index (cell) to be updated for the given value + int cellIndex; + + // correct offset + value -= lowerBound_; + + if( value < 0.0 ) + { + cellIndex = 0; + } + else + { + cellIndex = (int) (std::floor( value / cellWidth_ ) + 1); + + if( cellIndex > maxCellIndex_ ) + { + cellIndex = maxCellIndex_ ; + } else if (cellIndex < 0) { + cellIndex = 0; + } + } + + ++( cellData_[ cellIndex ].count ); +} + +void Histogram::reset( base::SimTime time ) +{ + Tally::reset( time ); + + // reset cell vector by swapping with a zero-initialized temporary + CellVec tmp( cellCount_, Cell() ); + cellData_.swap( tmp ); +} + +//-----------------------------------------------------------------------getters + +const Histogram::CellVec& Histogram::getData() +{ + // update() only sets the counters, + // must compute other cell values here + + // values < lower bound + cellData_[ 0 ].lowerBound = std::min( lowerBound_ - cellWidth_, getMin() ); + cellData_[ 0 ].upperBound = lowerBound_; + cellData_[ 0 ].percentage = (double)cellData_[ 0 ].count * 100 / getUpdateCount(); + + // regular values within bounds + for( size_t i = 1; i < cellCount_ - 1; ++i ) + { + cellData_[ i ].lowerBound = lowerBound_ + (i - 1) * cellWidth_; + cellData_[ i ].upperBound = lowerBound_ + i * cellWidth_; + cellData_[ i ].percentage = (double)cellData_[ i ].count * 100 / getUpdateCount(); + } + + // values > upper bound + cellData_[ cellCount_ - 1 ].lowerBound = upperBound_; + cellData_[ cellCount_ - 1 ].upperBound = std::max( upperBound_ + cellWidth_, getMax() ); + cellData_[ cellCount_ - 1 ].percentage = + (double)cellData_[ cellCount_ - 1 ].count * 100 / getUpdateCount(); + + return cellData_; +} + +//------------------------------------------------------------------------report + +void Histogram::report( data::Report& report ) +{ + using namespace data; + + ReportTable::Definition tallyDef; + tallyDef.addColumn( "Name", ReportTable::Column::STRING ); + tallyDef.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + tallyDef.addColumn( "Uses", ReportTable::Column::INTEGER ); + tallyDef.addColumn( "Low", ReportTable::Column::REAL ); + tallyDef.addColumn( "High", ReportTable::Column::REAL ); + tallyDef.addColumn( "Cells", ReportTable::Column::INTEGER ); + tallyDef.addColumn( "Min", ReportTable::Column::REAL ); + tallyDef.addColumn( "Max", ReportTable::Column::REAL ); + tallyDef.addColumn( "Mean", ReportTable::Column::REAL ); + tallyDef.addColumn( "Std Deviation", ReportTable::Column::REAL ); + ReportTable& statsTable = report.getTable( "Histogram Statistics Summary", tallyDef ); + statsTable + << getLabel() + << getResetTime() + << getUpdateCount() + << lowerBound_ + << upperBound_ + << cellCount_ + << getMin() + << getMax() + << getMean() + << getStandardDeviation(); + + ReportTable::Definition visualDef; + visualDef.addColumn( "Low", ReportTable::Column::REAL ); + visualDef.addColumn( "High", ReportTable::Column::REAL ); + visualDef.addColumn( "Count", ReportTable::Column::INTEGER ); + visualDef.addColumn( "Percentage", ReportTable::Column::REAL ); + visualDef.addColumn( "Bar Diagram", ReportTable::Column::BAR ); + + std::ostringstream tableName; + tableName << "Histogram: " << getLabel() << " [" << getUpdateCount() << " samples]"; + ReportTable& visualTable = report.getTable( tableName.str(), visualDef ); + + const CellVec& data = getData(); + + // compute multiplier for graphical representation + double maxPercentage = 0; + for( CellVec::const_iterator cellIter = data.begin(); + cellIter != data.end(); ++cellIter ) + { + const Cell& cell = *cellIter; + if( cell.percentage > maxPercentage ) + { + maxPercentage = cell.percentage; + } + } + // diagram width should be 100%, i.e. the maximum value should fill it + double multiplier = 0; + if( 0 < maxPercentage ) + { + multiplier = 100 / maxPercentage; + } + + // compute results + for( CellVec::const_iterator iter = data.begin(); iter != data.end(); ++iter ) + { + const Cell& current = *iter; + + long bar = (long) std::floor( multiplier * current.percentage ); + if( current.percentage - bar > 0.5 ) + { + ++bar; + } + + visualTable + << current.lowerBound + << current.upperBound + << current.count + << current.percentage + << bar; + } +}; + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/statistics/Regression.cpp b/odemx-lite/src/statistics/Regression.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ccc17a80ecd6563090d372e905b23f352071e6a --- /dev/null +++ b/odemx-lite/src/statistics/Regression.cpp @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Regression.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Regression + * @sa Regression.h + * @since 3.0 + */ + +#include <odemx/statistics/Regression.h> +#include <odemx/data/ReportTable.h> +#include <odemx/data/Report.h> + +#include <cmath> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Regression::Regression( base::Simulation& sim, const data::Label& label ) +: Tab( sim, label ) +, sumX_( 0.0 ) +, sumY_( 0.0 ) +, sumSqX_( 0.0 ) +, sumXMulY_( 0.0 ) +, sumSqY_( 0.0 ) +{ +} + +Regression::~Regression() +{ +} + +//---------------------------------------------------------------------modifiers + +void Regression::update( double valueX, double valueY) +{ + Tab::update(); + + sumX_ += valueX; + sumY_ += valueY; + sumSqX_ += std::pow( valueX, 2 ); + sumSqY_ += std::pow( valueY, 2 ); + sumXMulY_ += valueX * valueY; +} + +void Regression::reset( base::SimTime time ) +{ + Tab::reset( time ); + sumX_ = sumY_ = sumSqX_ = sumXMulY_ = sumSqY_ = 0.0; +} + +//-----------------------------------------------------------------------getters + +bool Regression::hasSufficientData() const +{ + return getUpdateCount() > 5; +} + +double Regression::getXMean() const +{ + return getUpdateCount() ? sumX_ / getUpdateCount() : 0.0; +} + +double Regression::getYMean() const +{ + return getUpdateCount() ? sumY_ / getUpdateCount() : 0.0; +} + +double Regression::getDx() const +{ + return std::fabs( getUpdateCount() * sumSqX_ - std::pow( sumX_, 2 ) ); +} + +double Regression::getDy() const +{ + return std::fabs( getUpdateCount() * sumSqY_ - std::pow( sumY_, 2 ) ); +} + +double Regression::getResidualStandardDeviation() const +{ + // RES.ST.DEV + double sd = std::sqrt( ( sumSqY_ - getIntercept() * sumY_ + - getEstimatedRegressionCoefficient() * sumXMulY_ ) + / (getUpdateCount() - 2 ) ); + return sd; +} + +double Regression::getEstimatedRegressionCoefficient() const +{ + // EST.REG.COEFF + double a1 = ( getUpdateCount() * sumXMulY_ - sumX_ * sumY_ ) / getDx(); + return a1; +} + +double Regression::getIntercept() const +{ + // INTERCEPT + double a0 = ( sumY_ * sumSqX_ - sumX_ * sumXMulY_ ) / getDx(); + return a0; +} + +double Regression::getRegressionCoefficientStandardDeviation() const +{ + // ST.DEV.REG.COEFF + return ( getUpdateCount() * getResidualStandardDeviation() + / std::sqrt( ( getUpdateCount() - 2 ) * getDx() ) ); +} + +double Regression::getCorrelationCoefficient() const +{ + // CORR.COEFF + double r2 = ( ( getUpdateCount() * sumXMulY_ - sumX_ * sumY_ ) + * ( getUpdateCount() * sumXMulY_ - sumX_ * sumY_ ) ) + / ( getDx() * getDy() ); + return r2; +} + +//------------------------------------------------------------------------report + +void Regression::report( data::Report& report ) +{ + using namespace data; + ReportTable::Definition def; + def.addColumn( "Name", ReportTable::Column::STRING ); + def.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + def.addColumn( "Uses", ReportTable::Column::INTEGER ); + def.addColumn( "XBar", ReportTable::Column::REAL ); + def.addColumn( "YBar", ReportTable::Column::REAL ); + def.addColumn( "Dx", ReportTable::Column::REAL ); + def.addColumn( "Dy", ReportTable::Column::REAL ); + def.addColumn( "Residual StDev", ReportTable::Column::REAL ); + def.addColumn( "Est Reg Coeff", ReportTable::Column::REAL ); + def.addColumn( "Intercept", ReportTable::Column::REAL ); + def.addColumn( "Reg Coeff StDev", ReportTable::Column::REAL ); + def.addColumn( "Correlation Coeff", ReportTable::Column::REAL ); + ReportTable& table = report.getTable( "Regression Statistics", def ); + table + << getLabel() + << getResetTime() + << getUpdateCount() + << getXMean() + << getYMean() + << getDx() + << getDy() + << getResidualStandardDeviation() + << getEstimatedRegressionCoefficient() + << getIntercept() + << getRegressionCoefficientStandardDeviation() + << getCorrelationCoefficient(); +} + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/statistics/Sum.cpp b/odemx-lite/src/statistics/Sum.cpp new file mode 100644 index 0000000000000000000000000000000000000000..043ab2f18d246515e8a3b9477dc8e8686c7384bd --- /dev/null +++ b/odemx-lite/src/statistics/Sum.cpp @@ -0,0 +1,86 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Sum.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Sum + * @sa Sum.h + * @since 3.0 + */ + +#include <odemx/statistics/Sum.h> +#include <odemx/data/ReportTable.h> +#include <odemx/data/Report.h> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Sum::Sum( base::Simulation& sim, const data::Label& label ) +: Tab( sim, label ) +, sum_( 0.0 ) +{ +} + +Sum::~Sum() +{ +} + +//---------------------------------------------------------------------modifiers + +void Sum::update( double value ) +{ + Tab::update(); + sum_ += value; +} + +void Sum::reset( base::SimTime time ) +{ + Tab::reset( time ); + sum_ = 0.0; +} + +//-----------------------------------------------------------------------getters + +double Sum::getValue() const +{ + return sum_; +} + +//------------------------------------------------------------------------report + +void Sum::report( data::Report& report ) +{ + using namespace data; + ReportTable::Definition def; + def.addColumn( "Name", ReportTable::Column::STRING ); + def.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + def.addColumn( "Uses", ReportTable::Column::INTEGER ); + def.addColumn( "Value", ReportTable::Column::REAL ); + ReportTable& table = report.getTable( "Sum Statistics", def ); + table + << getLabel() + << getResetTime() + << getUpdateCount() + << getValue(); +} + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/statistics/Tab.cpp b/odemx-lite/src/statistics/Tab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50a0c456e19072ce37dcb82f7d5098f46c8f148f --- /dev/null +++ b/odemx-lite/src/statistics/Tab.cpp @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Tab.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Tab + * @sa Tab.h + * @since 3.0 + */ + +#include <odemx/statistics/Tab.h> +#include <odemx/base/DefaultSimulation.h> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Tab::Tab( base::Simulation& sim, const data::Label& label ) +: ReportProducer( sim, label ) +, updateCount_( 0 ) +, resetTime_( sim.getTime() ) +{ +} + +Tab::~Tab() +{ +} + +//---------------------------------------------------------------------modifiers + +void Tab::update() +{ + ++updateCount_; +} + +void Tab::reset( base::SimTime time ) +{ + resetTime_ = time; + updateCount_ = 0; +} + +//-----------------------------------------------------------------------getters + +std::size_t Tab::getUpdateCount() const +{ + return updateCount_; +} + +base::SimTime Tab::getResetTime() const +{ + return resetTime_; +} + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/statistics/Tally.cpp b/odemx-lite/src/statistics/Tally.cpp new file mode 100644 index 0000000000000000000000000000000000000000..147ed141dae6ee0b4a5f876fc1e97d60113f99b3 --- /dev/null +++ b/odemx-lite/src/statistics/Tally.cpp @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Tally.cpp + * @author Ronald Kluth + * @date created at 2009/03/01 + * @brief Implementation of odemx::statistics::Tally + * @sa Tally.h + * @since 3.0 + */ + +#include <odemx/statistics/Tally.h> +#include <odemx/data/ReportTable.h> +#include <odemx/data/Report.h> + +#include <cmath> + +namespace odemx { +namespace statistics { + +//------------------------------------------------------construction/destruction + +Tally::Tally( base::Simulation& sim, const data::Label& label ) +: Tab( sim, label ) +, minValue_( 0.0 ) +, maxValue_( 0.0 ) +, sum_( 0.0 ) +, sumSq_( 0.0 ) +{ +} + +Tally::~Tally() +{ +} + +//---------------------------------------------------------------------modifiers + +void Tally::update( double value ) +{ + Tab::update(); + + sum_ += value; + sumSq_ += std::pow( value, 2 ); + + if( getUpdateCount() == 1 ) + { + minValue_ = maxValue_ = value; + } + else if( value < minValue_ ) + { + minValue_ = value; + } + else if( value > maxValue_ ) + { + maxValue_ = value; + } +} + +void Tally::reset( base::SimTime time ) +{ + Tab::reset( time ); + sum_ = sumSq_ = minValue_ = maxValue_ = 0.0; +} + +//-----------------------------------------------------------------------getters + +double Tally::getMin() const +{ + return minValue_; +} + +double Tally::getMax() const +{ + return maxValue_; +} + +double Tally::getMean() const +{ + return getUpdateCount() ? sum_ / getUpdateCount() : 0.0; +} + +double Tally::getStandardDeviation() const +{ + if( getUpdateCount() <= 1 ) + { + return 0.0; + } + + double mean = getMean(); + double variance = std::fabs( sumSq_ / getUpdateCount() - std::pow( mean, 2 ) ); + return std::sqrt( variance ); +} + +//------------------------------------------------------------------------report + +void Tally::report( data::Report& report ) +{ + using namespace data; + ReportTable::Definition def; + def.addColumn( "Name", ReportTable::Column::STRING ); + def.addColumn( "Reset at", ReportTable::Column::SIMTIME ); + def.addColumn( "Uses", ReportTable::Column::INTEGER ); + def.addColumn( "Min", ReportTable::Column::REAL ); + def.addColumn( "Max", ReportTable::Column::REAL ); + def.addColumn( "Mean", ReportTable::Column::REAL ); + def.addColumn( "Standard Deviation", ReportTable::Column::REAL ); + ReportTable& table = report.getTable( "Tally Statistics", def ); + table + << getLabel() + << getResetTime() + << getUpdateCount() + << getMin() + << getMax() + << getMean() + << getStandardDeviation(); +} + +} } // namespace odemx::statistics diff --git a/odemx-lite/src/synchronization/Bin.cpp b/odemx-lite/src/synchronization/Bin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6008238502b5d2306d2533a20e6ab8d66adb4288 --- /dev/null +++ b/odemx-lite/src/synchronization/Bin.cpp @@ -0,0 +1,201 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Bin.cpp + + \author Ralf Gerstenberger + + \date created at 2002/03/26 + + \brief Implementation of odemx::sync::Bin + + \sa Bin.h + + \since 1.0 +*/ + +#include <odemx/synchronization/Bin.h> +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> + +#include <cassert> + +namespace odemx { +namespace synchronization { + +Bin::Bin( base::Simulation& sim, const data::Label& label, std::size_t initialTokens, BinObserver* obs ) +: data::Producer( sim, label ) +, data::Observable< BinObserver >( obs ) +, tokens_( initialTokens ) +, takeQueue_( sim, getLabel() + " queue" ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Bin) ); + + statistics << param( "queue", takeQueue_.getLabel() ).scope( typeid(Bin) ); + statistics << param( "initial tokens", initialTokens ).scope( typeid(Bin) ); + statistics << update( "tokens", tokens_ ).scope( typeid(Bin) ); + + // observer + ODEMX_OBS(BinObserver, Create(this)); +} + +Bin::~Bin() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Bin) ); +} + +std::size_t Bin::take( std::size_t n ) +{ + // resource handling only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "Bin::take(): called by non-Process object" ) + .scope( typeid(Bin) ); + return 0; + } + + base::Process* currentProcess = getCurrentProcess(); + + // compute order of service, insert the process into the queue + takeQueue_.inSort( currentProcess ); + + // if not enough tokens or not the first process to serve + if( n > tokens_ || currentProcess != takeQueue_.getTop() ) + { + ODEMX_TRACE << log( "take failed" ) + .detail( "partner", getPartner() ) + .detail( "requested tokens", n ) + .scope( typeid(Bin) ); + + // observer + ODEMX_OBS(BinObserver, TakeFail(this, n)); + + // statistics + base::SimTime waitStart = getTime(); + + // block execution + while( n > tokens_ || currentProcess != takeQueue_.getTop() ) + { + currentProcess->sleep(); + + if( currentProcess->isInterrupted() ) + { + takeQueue_.remove( currentProcess ); + return 0; + } + } + // block released here + + // statistics, log the waiting period + base::SimTime waitTime = getTime() - waitStart; + statistics << update( "wait time", waitTime ).scope( typeid(Bin) ); + } + + ODEMX_TRACE << log( "change token number" ).valueChange( tokens_, tokens_ - n ) + .scope( typeid(Bin) ); + + // observer + ODEMX_OBS_ATTR(BinObserver, TokenNumber, tokens_, tokens_ - n); + + // take tokens + tokens_ -= n; + + ODEMX_TRACE << log( "take succeeded" ) + .detail( "partner", getPartner() ) + .detail( "requested tokens", n ) + .scope( typeid(Bin) ); + + // statistics + statistics << count( "users" ).scope( typeid(Bin) ); + statistics << update( "tokens", tokens_ ).scope( typeid(Bin) ); + + // observer + ODEMX_OBS(BinObserver, TakeSucceed(this, n)); + + // remove from list + takeQueue_.remove( currentProcess ); + + // awake next process + awakeFirst( &takeQueue_ ); + + return n; +} + +void Bin::give( std::size_t n ) +{ + ODEMX_TRACE << log( "change token number" ).valueChange( tokens_, tokens_ + n ) + .scope( typeid(Bin) ); + + // observer + ODEMX_OBS_ATTR(BinObserver, TokenNumber, tokens_, tokens_+n); + + // release tokens + tokens_ += n; + + ODEMX_TRACE << log( "give" ) + .detail( "partner", getPartner() ) + .detail( "given tokens", n ) + .scope( typeid(Bin) ); + + // statistics + statistics << count( "providers" ).scope( typeid(Bin) ); + statistics << update( "tokens", tokens_ ).scope( typeid(Bin) ); + + // observer + ODEMX_OBS(BinObserver, Give(this, n)); + + // awake next process + awakeFirst( &takeQueue_ ); +} + +std::size_t Bin::getTokenNumber() const +{ + return tokens_; +} + +const base::ProcessList& Bin::getWaitingProcesses() const +{ + return takeQueue_.getList(); +} + +base::SimTime Bin::getTime() const +{ + return getSimulation().getTime(); +} + +base::Sched* Bin::getCurrentSched() +{ + return getSimulation().getCurrentSched(); +} + +base::Process* Bin::getCurrentProcess() +{ + return getSimulation().getCurrentProcess(); +} + +const data::Label& Bin::getPartner() +{ + if( getSimulation().getCurrentSched() != 0 ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + + return getSimulation().getLabel(); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/CondQ.cpp b/odemx-lite/src/synchronization/CondQ.cpp new file mode 100644 index 0000000000000000000000000000000000000000..08098e32ba22414eab1af65559491bbf33cbec91 --- /dev/null +++ b/odemx-lite/src/synchronization/CondQ.cpp @@ -0,0 +1,156 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file CondQ.cpp + + \author Ralf Gerstenberger + + \date created at 2002/07/11 + + \brief Implementation of odemx::sync::CondQ + + \sa CondQ.h + + \since 1.0 +*/ + +#include <odemx/synchronization/CondQ.h> +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> + +#include <cassert> +#include <string> + +namespace odemx { +namespace synchronization { + +CondQ::CondQ( base::Simulation& sim, const data::Label& label, CondQObserver* obs ) +: data::Producer( sim, label ) +, data::Observable< CondQObserver >( obs ) +, processes_( sim, getLabel() + ".queue" ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(CondQ) ); + + statistics << param( "queue", processes_.getLabel() ).scope( typeid(CondQ) ); + + // observer + ODEMX_OBS(CondQObserver, Create(this)); +} + +CondQ::~CondQ() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(CondQ) ); +} + +bool CondQ::wait( base::Condition cond ) +{ + // resource handling only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "CondQ::wait(): called by non-Process object" ) + .scope( typeid(CondQ) ); + return false; + } + + base::Process* currentProcess = getCurrentProcess(); + + ODEMX_TRACE << log( "wait" ).detail( "partner", currentProcess->getLabel() ) + .scope( typeid(CondQ) ); + + // observer + ODEMX_OBS(CondQObserver, Wait(this, currentProcess)); + + // wait for condition to become true + processes_.inSort( currentProcess ); + + // statistics + base::SimTime waitStart = getTime(); + + // check condition and block + while( ! cond(currentProcess) ) + { + currentProcess->sleep(); + + if( currentProcess->isInterrupted() ) + { + processes_.remove( currentProcess ); + + return false; + } + } + // block released + + processes_.remove( currentProcess ); + + ODEMX_TRACE << log( "continue" ).detail( "partner", currentProcess->getLabel() ) + .scope( typeid(CondQ) ); + + // statistics + base::SimTime waitTime = getTime() - waitStart; + statistics << update( "wait time", waitTime ).scope( typeid(CondQ) ); + statistics << count( "users" ).scope( typeid(CondQ) ); + + // observer + ODEMX_OBS(CondQObserver, Continue(this, currentProcess)); + + return true; +} + +void CondQ::signal() +{ + base::Process* current = getCurrentProcess(); + + ODEMX_TRACE << log( "signal" ) + .detail( "partner", ( current ? current->getLabel() : "none" ) ) + .scope( typeid(CondQ) ); + + // observer + ODEMX_OBS(CondQObserver, Signal(this, current)); + + statistics << count( "signals" ).scope( typeid(CondQ) ); + + if( processes_.isEmpty() ) + { + return; + } + + // test conditions + awakeAll( &processes_ ); +} + +const base::ProcessList& CondQ::getWaitingProcesses() const +{ + return processes_.getList(); +} + +base::SimTime CondQ::getTime() const +{ + return getSimulation().getTime(); +} + +base::Sched* CondQ::getCurrentSched() +{ + return getSimulation().getCurrentSched(); +} + +base::Process* CondQ::getCurrentProcess() +{ + return getSimulation().getCurrentProcess(); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/IMemory.cpp b/odemx-lite/src/synchronization/IMemory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..534bd9ab4a60f8b647015dad74a701976494ea26 --- /dev/null +++ b/odemx-lite/src/synchronization/IMemory.cpp @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file IMemory.cpp + * @author Ronald Kluth + * @date created at 2009/02/11 + * @brief Implementation of odemx::sync::IMemory + * @since 3.0 + */ + +#include <odemx/synchronization/IMemory.h> + +namespace odemx { +namespace synchronization { + +IMemory::~IMemory() +{ +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/Memory.cpp b/odemx-lite/src/synchronization/Memory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..000b50aacbffb5f29275603e35219721daa799b9 --- /dev/null +++ b/odemx-lite/src/synchronization/Memory.cpp @@ -0,0 +1,281 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002 - 2008 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Memory.cpp + + \author Ronald Kluth + + \date created at 2007/04/04 + + \brief Implementation of odemx::sync::Memory + + \sa Memory.h + + \since 2.0 +*/ + +#include <odemx/base/Process.h> +#include <odemx/base/DefaultSimulation.h> +#include <odemx/synchronization/Memory.h> +#include <CppLog/Channel.h> + +#include <algorithm> +#ifdef _MSC_VER +#include <functional> +#else +#include <functional> +#endif + + +namespace odemx { +namespace synchronization { + +Memory::Memory( base::Simulation& sim, const data::Label& label, Type type, + MemoryObserver* obs ) +: data::Producer( sim, label ) +, data::Observable< MemoryObserver >( obs ) +, memoryType_( type ) +, memoryList_() +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Memory) ); + + statistics << update( "waiting", countWaiting() ).scope( typeid(Memory) ); + + // observer + ODEMX_OBS(MemoryObserver, Create(this)); +} + +Memory::~Memory() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Memory) ); +} + +bool Memory::remember( base::Sched* newObject ) +{ + assert( newObject ); + + // check if object is already memorized + base::SchedList::const_iterator found = + std::find( memoryList_.begin(), memoryList_.end(), newObject ); + + if ( found != memoryList_.end() ) + { + warning << log( "Memory::remember(): object already stored in list" ) + .detail( "partner", newObject->getLabel() ) + .scope( typeid(Memory) ); + + return false; + } + + // store the new object + memoryList_.push_back( newObject ); + + ODEMX_TRACE << log( "remember" ).detail( "partner", newObject->getLabel() ) + .scope( typeid(Memory) ); + + statistics << update( "waiting", countWaiting() ).scope( typeid(Memory) ); + + // observer + ODEMX_OBS( MemoryObserver, Remember( this, newObject ) ); + + return true; +} + +bool Memory::forget( base::Sched* rememberedObject ) +{ + assert( rememberedObject ); + + // check if rememberedObject is in memoryList_ + base::SchedList::iterator found = + std::find( memoryList_.begin(), memoryList_.end(), rememberedObject ); + + // error if not found + if( found == memoryList_.end() ) + { + error << log( "Memory::forget(): object not stored in list" ) + .detail( "partner", rememberedObject->getLabel() ) + .scope( typeid(Memory) ); + + return false; + } + + // remove the object from the list + memoryList_.erase( found ); + + ODEMX_TRACE << log( "forget" ).detail( "partner", rememberedObject->getLabel() ) + .scope( typeid(Memory) ); + + statistics << update( "waiting", countWaiting() ).scope( typeid(Memory) ); + + // observer + ODEMX_OBS( MemoryObserver, Forget( this, rememberedObject ) ); + + return true; +} + +bool Memory::processIsWaiting (base::Process& process) const { + base::SchedList::const_iterator found = + std::find( memoryList_.begin(), memoryList_.end(), &process ); + return found != memoryList_.end (); +} + +void Memory::eraseMemory() +{ + memoryList_.clear(); + + ODEMX_TRACE << log( "erase" ).scope( typeid(Memory) ); + + statistics << update( "waiting", countWaiting() ).scope( typeid(Memory) ); +} + +void Memory::alert() +{ + alert( this ); +} + +void Memory::alert( IMemory* caller ) +{ + assert( caller ); + + // warning if list is empty + if( memoryList_.empty() ) + { + warning << log( "Memory::alert(): list empty, cannot alert any object" ) + .scope( typeid(Memory) ); + return; + } + + // trace record with the whole memory list as details + traceAlert(); + + // observer + ODEMX_OBS( MemoryObserver, Alert( this ) ); + + // iterate over memoryList_ and schedule processes + base::SchedList::iterator iter; + for( iter = memoryList_.begin(); iter != memoryList_.end(); ++iter ) + { + // check if Sched* really is a sleeping process and + // reschedule CREATED and IDLE processes in memory + if( checkSchedForAlert( *iter ) ) + { + // wake up the process + static_cast< base::Process* >( *iter )->alertProcess( caller ); + } + else + { + warning << log( "Memory::alert(): could not alert Sched object" ) + .detail( "partner", ( *iter )->getLabel() ) + .scope( typeid(Memory) ); + } + } + + // remove stored objects from memory + eraseMemory(); +} + +bool Memory::checkSchedForAlert( base::Sched* s ) +{ + assert( s ); + + // check if s really is a sleeping process + if( s->getSchedType() != base::Sched::PROCESS ) + { + warning << log( "Memory::checkSchedForAlert(): object is not a process" ) + .detail( "partner", s->getLabel() ) + .scope( typeid(Memory) ); + return false; + } + + base::Process* p = static_cast< base::Process* >( s ); + + // only sleeping Processes are allowed to be alerted + switch( p->getProcessState() ) + { + case base::Process::CREATED: // fall-through + case base::Process::IDLE: + return true; + + case base::Process::CURRENT: + warning << log( "Memory::checkSchedForAlert(): attempt to alert current process" ) + .detail( "partner", p->getLabel() ) + .scope( typeid(Memory) ); + break; + + case base::Process::RUNNABLE: + warning << log( "Memory::checkSchedForAlert(): process already scheduled" ) + .detail( "partner", p->getLabel() ) + .scope( typeid(Memory) ); + break; + + case base::Process::TERMINATED: + error << log( "Memory::checkSchedForAlert(): process already terminated" ) + .detail( "partner", p->getLabel() ) + .scope( typeid(Memory) ); + break; + + } + return false; +} + +bool Memory::isAvailable() +{ + return false; +} + + +bool Memory::waiting() const +{ + return ! memoryList_.empty(); +} + +Memory::SizeType Memory::countWaiting() const +{ + return memoryList_.size(); +} + +const base::SchedList& Memory::getWaiting() const +{ + return memoryList_; +} + +IMemory::Type Memory::getMemoryType() const +{ + return memoryType_; +} + +void Memory::traceAlert() +{ + if( ODEMX_TRACE_ENABLED ) + { + // create record for alert with scope Memory + data::SimRecord record = log( "alert" ).scope( typeid(Memory) ); + + // add record details: stored objects + base::SchedList::const_iterator iter; + for( iter = memoryList_.begin(); iter != memoryList_.end(); ++iter ) + { + record.detail( "partner", ( *iter )->getLabel() ); + } + + // log the record to the trace + ODEMX_TRACE << record; + } +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/ProcessQueue.cpp b/odemx-lite/src/synchronization/ProcessQueue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d059d7126a45ec8c31f2020d9489b0414dc23300 --- /dev/null +++ b/odemx-lite/src/synchronization/ProcessQueue.cpp @@ -0,0 +1,232 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2002, 2004, 2007, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file ProcessQueue.cpp + * @author Ralf Gerstenberger + * @date created at 2002/03/25 + * @brief Implementation of odemx::sync::ProcessQueue + * @sa ProcessQueue.h + * @since 1.0 + */ + +#include <odemx/synchronization/ProcessQueue.h> +#include <odemx/base/Comparators.h> +#include <odemx/base/Process.h> +#include <odemx/util/ListInSort.h> + +#include <algorithm> + +namespace odemx { +namespace synchronization { + +//------------------------------------------------------construction/destruction + +ProcessQueue::ProcessQueue() +: processes_() +, length_( 0 ) +{ +} + +ProcessQueue::~ProcessQueue() +{ +} + +//------------------------------------------------------------------queue access + +bool ProcessQueue::isEmpty() const +{ + return processes_.empty(); +} + +base::Process* ProcessQueue::getTop() const +{ + return processes_.empty() ? 0 : *processes_.begin(); +} + +const base::ProcessList& ProcessQueue::getList() const +{ + return processes_; +} + +ProcessQueue::SizeType ProcessQueue::getLength() const +{ + return length_; // a lot faster than calling list::size() +} + +ProcessQueue::SizeType ProcessQueue::getPosition( base::Process* p ) const +{ + assert( p != 0 ); + + SizeType pos = 1; + + base::ProcessList::const_iterator iter = processes_.begin(); + + // count positions until p is found + while( iter != processes_.end() && ( *iter ) != p ) + { + ++pos; + ++iter; + } + + // check if p was found + if( iter != processes_.end() && ( *iter ) == p ) + { + return pos; + } + + return 0; +} + +//------------------------------------------------------------queue manipulation + +void ProcessQueue::popQueue() +{ + if( ! processes_.empty() ) + { + ProcessQueue::remove( *processes_.begin() ); + } +} + +void ProcessQueue::remove( base::Process* p ) +{ + assert( p != 0 ); + + // Process p forgets this queue + p->dequeue( this ); + + processes_.erase( p->queueListIter_ ); + --length_; +} + +void ProcessQueue::inSort( base::Process* p, bool fifo ) +{ + assert( p != 0 ); + + // if already in this queue, remove previous entry of Process* p + if( p->queue_ == this ) + { + processes_.erase( p->queueListIter_ ); + p->queue_ = 0; // queue_ != 0 would cause error in Process::enqueue() + } + // not yet in queue, increment size + else + { + ++length_; + } + + // Process p has to remember this queue + p->enqueue( this ); + + // insert s into ordered list and store the location as iterator + p->queueListIter_ = + ListInSort< base::Process*, base::QPriorityCmp >( + processes_, p, base::qPrioCmp, fifo ); +} + +//----------------------------------------------------------free queue functions + +void awakeAll( ProcessQueue* q ) +{ + if( q->isEmpty() ) + { + return; + } + + base::Sched* currentlyRunning = q->getTop()->getCurrentSched(); // may return 0 ! + + base::ProcessList::const_iterator i; + for( i = q->getList().begin(); i != q->getList().end(); ++i ) + { + base::Process* p = *i; + + assert( static_cast< base::Sched* >( p ) != currentlyRunning ); + + // cannot activate after current event, must use activate + if( ! currentlyRunning || currentlyRunning->getSchedType() == base::Sched::EVENT ) + { + p->activate(); + } + else // a process is currently running + { + p->activateAfter( currentlyRunning ); + } + } +} + +void awakeFirst( ProcessQueue* q ) +{ + if( q->isEmpty() ) + { + return; + } + + base::Sched* current = q->getTop()->getCurrentSched(); // may return 0 ! + + // cannot activate after current event, must use activate + if( ! current || current->getSchedType() == base::Sched::EVENT ) + { + q->getTop()->activate(); + } + else + { + if( q->getTop() != current ) + { + q->getTop()->activateAfter( current ); + } + } +} + +void awakeNext( ProcessQueue* q, base::Process* p ) +{ + if( q->isEmpty() ) + { + return; + } + + base::Sched* current = p->getCurrentSched(); // may return 0 ! + + base::ProcessList::const_iterator iter = std::find( q->getList().begin(), q->getList().end(), p ); + + // check if p was found + if( iter != q->getList().end() ) + { + ++iter; + + // check if next position is valid + if( iter != q->getList().end() ) + { + base::Process* p = *iter; + + // cannot activate after current event, must use activate + if( ! current || current->getSchedType() == base::Sched::EVENT ) + { + p->activate(); + } + else + { + if( p != current ) + { + p->activateAfter( current ); + } + } + } + } +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/Queue.cpp b/odemx-lite/src/synchronization/Queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9aca0bfb6a01cd62a4a63d09df7d5d558a55aee --- /dev/null +++ b/odemx-lite/src/synchronization/Queue.cpp @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// Copyright (C) 2003, 2004, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//------------------------------------------------------------------------------ + +/** + * @file Queue.cpp + * @author Ralf Gerstenberger + * @date created at 2003/06/28 + * @brief Implementation of odemx::sync::Queue + * @sa Queue.h + * @since 1.0 + */ + +#ifdef _MSC_VER +#pragma warning (disable : 4786) +#endif + +#include <odemx/synchronization/Queue.h> +#include <odemx/base/Process.h> + +#include <string> +#include <vector> + +namespace odemx { +namespace synchronization { + +//------------------------------------------------------construction/destruction + +Queue::Queue( base::Simulation& sim, const data::Label& label ) +: data::Producer( sim, label ) +, ProcessQueue() +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Queue) ); + statistics << update( "length", getLength() ).scope( typeid(Queue) ); +} + +Queue::~Queue() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Queue) ); +} + +//------------------------------------------------------------queue manipulation + +void Queue::popQueue() +{ + base::Process* first = ProcessQueue::getTop(); + ProcessQueue::popQueue(); + + if( first != 0 ) + { + ODEMX_TRACE << log( "pop queue" ) + .detail( "process", first->getLabel() ) + .scope( typeid(Queue) ); + } + else + { + warning << log( "Queue::popQueue(): called on empty queue" ) + .scope( typeid(Queue) ); + } + + statistics << update( "length", getLength() ).scope( typeid(Queue) ); +} + +void Queue::remove( base::Process* p ) +{ + assert( p ); + + ProcessQueue::remove( p ); + + ODEMX_TRACE << log( "remove" ) + .detail( "process", p->getLabel() ) + .scope( typeid(Queue) ); + + statistics << update( "length", getLength() ).scope( typeid(Queue) ); +} + +void Queue::inSort( base::Process* p, bool fifo ) +{ + assert( p ); + + ProcessQueue::inSort( p, fifo ); + + ODEMX_TRACE << log( "insert" ) + .detail( "process", p->getLabel() ) + .scope( typeid(Queue) ); + + statistics << update( "length", getLength() ).scope( typeid(Queue) ); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/Res.cpp b/odemx-lite/src/synchronization/Res.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f068760ff541f6de93245a77e5f10d871b2472bf --- /dev/null +++ b/odemx-lite/src/synchronization/Res.cpp @@ -0,0 +1,269 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Res.cpp + + \author Ralf Gerstenberger + + \date created at 2002/03/21 + + \brief Implementation of odemx::sync::Res + + \sa Res.h + + \since 1.0 +*/ + +#include <odemx/synchronization/Res.h> +#include <odemx/base/Process.h> +#include <odemx/base/Simulation.h> + +#include <algorithm> +#include <cassert> +#include <string> + +namespace odemx { +namespace synchronization { + +Res::Res( base::Simulation& sim, const data::Label& label, std::size_t initialTokens, + std::size_t maxTokens, ResObserver* obs ) +: data::Producer( sim, label ) +, data::Observable< ResObserver >( obs ) +, tokens_( initialTokens ) +, tokenLimit_( maxTokens ) +, acquireQueue_( sim, getLabel() + ".queue" ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Res) ); + + statistics << param( "queue", acquireQueue_.getLabel() ).scope( typeid(Res) ); + statistics << param( "initial tokens", initialTokens ).scope( typeid(Res) ); + statistics << param( "initial token limit", tokenLimit_ ).scope( typeid(Res) ); + statistics << update( "tokens", tokens_ ).scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, Create(this)); +} + +Res::~Res() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Res) ); +} + +std::size_t Res::acquire( std::size_t n ) +{ + // resource handling only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "Res::acquire(): called by non-Process object" ) + .scope( typeid(Res) ); + return 0; + } + + if( n > getTokenLimit() ) + { + warning << log( "Res::acquire(): requesting more than max tokens will always block" ) + .scope( typeid(Res) ); + } + + base::Process* currentProcess = getCurrentProcess(); + + // compute order of service + acquireQueue_.inSort( currentProcess ); + + // statistics + base::SimTime waitTime = 0; + + // if not enough tokens or not the first process to serve + if( n > tokens_ || currentProcess != acquireQueue_.getTop() ) + { + ODEMX_TRACE << log( "acquire failed" ) + .detail( "partner", getPartner() ) + .detail( "requested tokens", n ) + .scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, AcquireFail(this, n)); + + // statistics + base::SimTime waitStart = getTime(); + + // block execution + while( n > tokens_ || currentProcess != acquireQueue_.getTop() ) + { + currentProcess->sleep(); + + if( currentProcess->isInterrupted() ) + { + acquireQueue_.remove( currentProcess ); + return 0; + } + } + // block released here + + // statistics + waitTime = getTime() - waitStart; + } + + ODEMX_TRACE << log( "change token number" ).valueChange( tokens_, tokens_ - n ) + .scope( typeid(Res) ); + + // observer + ODEMX_OBS_ATTR(ResObserver, TokenNumber, tokens_, tokens_-n); + + // acquire tokens + tokens_ -= n; + + ODEMX_TRACE << log( "acquire succeeded" ) + .detail( "partner", getPartner() ) + .detail( "requested tokens", n ) + .scope( typeid(Res) ); + + // statistics + statistics << count( "users" ).scope( typeid(Res) ); + statistics << update( "tokens", tokens_ ).scope( typeid(Res) ); + statistics << update( "wait time", waitTime ).scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, AcquireSucceed(this, n)); + + // remove from list + acquireQueue_.remove( currentProcess ); + + // awake next process + awakeFirst( &acquireQueue_ ); + + return n; +} + +void Res::release( std::size_t n ) +{ + // check for sufficient release space + if( ( tokens_ + n ) > tokenLimit_ ) + { + ODEMX_TRACE << log( "release failed" ) + .detail( "partner", getPartner() ) + .detail( "released tokens", n ) + .scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, ReleaseFail(this, n)); + + error << log( "Res::release(): limit reached, could not release all tokens" ) + .scope( typeid(Res) ); + + // set released token number to whatever space was left + n = tokenLimit_ - tokens_; + } + + ODEMX_TRACE << log( "change token number" ).valueChange( tokens_, tokens_ + n ) + .scope( typeid(Res) ); + + // observer + ODEMX_OBS_ATTR(ResObserver, TokenNumber, tokens_, tokens_ + n); + + // release tokens + tokens_ += n; + + statistics << count( "providers" ).scope( typeid(Res) ); + statistics << update( "tokens", tokens_ ).scope( typeid(Res) ); + + ODEMX_TRACE << log( "release succeeded" ) + .detail( "partner", getPartner() ) + .detail( "released tokens", n ) + .scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, ReleaseSucceed(this, n)); + + // awake process waiting for release + awakeFirst( &acquireQueue_ ); +} + +void Res::control( std::size_t n ) +{ + ODEMX_TRACE << log( "increase token limit" ) + .detail( "amount", n ).scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, Control(this, n)); + + // change max token limit + tokenLimit_ += n; + + // add tokens + release( n ); +} + +std::size_t Res::unControl( std::size_t n ) +{ + ODEMX_TRACE << log( "decrease token limit" ) + .detail( "amount", n ).scope( typeid(Res) ); + + // observer + ODEMX_OBS(ResObserver, UnControl(this, n)); + + // secure enough tokens + std::size_t tmp = acquire( n ); + + // remove tokens + tokenLimit_ -= tmp; + + return tmp; +} + +std::size_t Res::getTokenNumber() const +{ + return tokens_; +} + +std::size_t Res::getTokenLimit() const +{ + return tokenLimit_; +} + +const base::ProcessList& Res::getWaitingProcesses() const +{ + return acquireQueue_.getList(); +} + +base::SimTime Res::getTime() const +{ + return getSimulation().getTime(); +} + +base::Sched* Res::getCurrentSched() +{ + return getSimulation().getCurrentSched(); +} + +base::Process* Res::getCurrentProcess() +{ + return getSimulation().getCurrentProcess(); +} + +const data::Label& Res::getPartner() +{ + if( getSimulation().getCurrentSched() != 0 ) + { + return getSimulation().getCurrentSched()->getLabel(); + } + + return getSimulation().getLabel(); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/Timer.cpp b/odemx-lite/src/synchronization/Timer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45e880d22a96b82121d56a63d7ce9dfc0ee37c8d --- /dev/null +++ b/odemx-lite/src/synchronization/Timer.cpp @@ -0,0 +1,241 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2007, 2008, 2009 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Timer.cpp + + \author Ronald Kluth + + \date created at 2007/04/04 + + \brief Implementation of odemx::sync::Timer + + \sa Timer.h + + \since 2.0 +*/ + +#include <odemx/synchronization/Timer.h> +#include <odemx/base/Process.h> + +#include <cassert> + +namespace odemx { +namespace synchronization { + +const int MAX_PRIORITY = 0xffff; + +//------------------------------------------------------construction/destruction + +Timer::Timer( base::Simulation& sim, const data::Label& label, TimerObserver* obs ) +: Event( sim, label, obs ) +, data::Observable< TimerObserver >( obs ) +, memory_( sim, getLabel() + ".memory", IMemory::TIMER ) +{ + setPriority( MAX_PRIORITY ); + + ODEMX_TRACE << log( "create" ).scope( typeid(Timer) ); + + // observer + ODEMX_OBS(TimerObserver, Create(this)); +} + +Timer::~Timer() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Timer) ); + + // destruction of scheduled timers might crash + // the simulation, hence remove them here + if( isSet() ) + { + stop(); + } +} + +//--------------------------------------------------------------------scheduling + +void Timer::setIn( base::SimTime t ) +{ + // cannot schedule Timer + if( t < 0 ) + { + error << log( "Timer::setIn(): cannot schedule Timer, invalid SimTime < 0" ) + .scope( typeid(Timer) ); + return; + } + + ODEMX_TRACE << log( "set in" ).detail( "relative time", t ).scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, SetIn( this, t ) ); + + // scheduling + scheduleIn( t ); +} + +void Timer::setAt( base::SimTime t ) +{ + // cannot schedule Timer + if ( t < getTime() ) + { + error << log( "Timer::setAt(): cannot schedule Timer, SimTime already passed" ) + .scope( typeid(Timer) ); + return; + } + + ODEMX_TRACE << log( "set at" ).detail( "absolute time", t ).scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, SetAt( this, t ) ); + + // scheduling + scheduleAt( t ); +} + +void Timer::reset( base::SimTime t ) +{ + if( ! isScheduled() ) + { + warning << log( "Timer::reset(): scheduling of idle Timer using reset" ) + .scope( typeid(Timer) ); + } + + // cannot schedule Timer + if( t < 0 ) + { + error << log( "Timer::reset(): cannot schedule Timer, invalid SimTime < 0" ) + .scope( typeid(Timer) ); + return; + } + + ODEMX_TRACE << log( "reset" ).detail( "relative time", t ).scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, Reset( this, getExecutionTime(), t ) ); + + // scheduling + scheduleIn( t ); +} + +void Timer::stop() +{ + ODEMX_TRACE << log( "stop" ).scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, Stop( this ) ); + + // error check done in removeFromSchedule + removeFromSchedule(); + + // remove all waiting processes from Memory + eraseMemory(); +} + +bool Timer::isSet() +{ + return isScheduled(); +} + +//-----------------------------------------------------------Process interaction + +bool Timer::registerProcess( base::Process* p ) +{ + assert( p ); + + ODEMX_TRACE << log( "register process" ) + .detail( "partner", p->getLabel() ) + .scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, RegisterProcess( this, p ) ); + + return remember( p ); +} + +bool Timer::removeProcess( base::Process* p ) +{ + assert( p ); + + ODEMX_TRACE << log( "remove process" ) + .detail( "partner", p->getLabel() ) + .scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, RemoveProcess( this, p ) ); + + return forget( p ); +} + +//----------------------------------------------------------Event implementation + +void Timer::eventAction() +{ + ODEMX_TRACE << log( "timeout" ).scope( typeid(Timer) ); + + // observer + ODEMX_OBS( TimerObserver, Timeout( this ) ); + + if( ! memory_.waiting() ) + { + warning << log( "Timer::eventAction(): memory empty, cannot alert any process" ) + .scope( typeid(Timer) ); + } + else + { + // reschedule registered processes + alert(); + } +} + +//--------------------------------------------------------IMemory implementation + +IMemory::Type Timer::getMemoryType() const +{ + return memory_.getMemoryType(); +} + +bool Timer::isAvailable() +{ + return ! Event::isScheduled(); +} + +void Timer::alert() +{ + memory_.alert( this ); +} + +bool Timer::remember( base::Sched* newObject ) +{ + return memory_.remember( newObject ); +} + +bool Timer::forget( base::Sched* rememberedObject ) +{ + return memory_.forget( rememberedObject ); +} + +void Timer::eraseMemory() +{ + memory_.eraseMemory(); +} + +const base::SchedList& Timer::getWaiting() const +{ + return memory_.getWaiting(); +} + +} } // namespace odemx::sync diff --git a/odemx-lite/src/synchronization/Wait.cpp b/odemx-lite/src/synchronization/Wait.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8be0c8990fff879b0a59ca77b7f502ef154b5da0 --- /dev/null +++ b/odemx-lite/src/synchronization/Wait.cpp @@ -0,0 +1,261 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2003, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file Wait.cpp + + \author Ralf Gerstenberger + + \date created at 2003/06/06 + + \brief Implementation of classes in Wait.h + + \sa Wait.h + + \since 1.0 +*/ + +#include <odemx/setup.h> + +#ifdef ODEMX_USE_OBSERVATION + +#include <odemx/synchronization/Wait.h> +#include <odemx/base/Simulation.h> + +namespace odemx { +namespace synchronization { + +Wait::Wait( base::Simulation& sim, const data::Label& label ) +: data::Producer( sim, label ) +, waitForAll_( true ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Wait) ); +} + +Wait::Wait( base::Simulation& sim, const data::Label& label, base::Process* p1 ) +: data::Producer( sim, label ) +, waitForAll_( true ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Wait) ); + + base::Process* ppP[1] = { p1 }; + initObservedList( 1, ppP ); +} + +Wait::Wait( base::Simulation& sim, const data::Label& label, base::Process* p1, + base::Process* p2, bool all ) +: data::Producer( sim, label ) +, waitForAll_( all ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Wait) ); + + base::Process* ppP[2] = { p1, p2 }; + initObservedList( 2, ppP ); +} + +Wait::Wait( base::Simulation& sim, const data::Label& label, base::Process* p1, + base::Process* p2, base::Process* p3, bool all ) +: data::Producer( sim, label ) +, waitForAll_( all ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Wait) ); + + base::Process* ppP[3] = { p1, p2, p3 }; + initObservedList( 3, ppP ); +} + +Wait::Wait( base::Simulation& sim, const data::Label& label, int size, + base::Process* p[], bool all ) +: data::Producer( sim, label ) +, waitForAll_( all ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(Wait) ); + + initObservedList( size, p ); +} + +Wait::~Wait() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(Wait) ); +} + +void Wait::addProcess( base::Process* p ) +{ + assert( p ); + + ODEMX_TRACE << log( "add process" ).detail( "partner", p->getLabel() ).scope( typeid(Wait) ); + + observedProcesses_.push_back( p ); +} + +void Wait::removeProcess( base::Process* p ) +{ + assert( p ); + + ODEMX_TRACE << log( "remove process" ).detail( "partner", p->getLabel() ).scope( typeid(Wait) ); + + observedProcesses_.remove(p); +} + +const base::ProcessList& Wait::getWaitingProcesses() const +{ + return observedProcesses_; +} + +bool Wait::getCondition() const +{ + return waitForAll_; +} + +void Wait::setCondition( bool all ) +{ + waitForAll_ = all; +} + +void Wait::onChangeProcessState( base::Process* sender, + base::Process::ProcessState oldState, + base::Process::ProcessState newState ) +{ + if( newState == base::Process::TERMINATED ) + { + // check condition + waitCaller_->activate(); + + // remove sender from observed list, no need to check it again + observedProcesses_.remove( sender ); + + // remove this as observer of the sender + sender->data::Observable< base::ProcessObserver >::removeObserver( this ); + } +} + +bool Wait::wait() +{ + // store the caller that wants to be awakened + // upon termination of other processes + waitCaller_ = getSimulation().getCurrentProcess(); + + ODEMX_TRACE << log( "wait" ) + .detail( "partner", waitCaller_->getLabel() ) + .scope( typeid(Wait) ); + + base::ProcessList::iterator i; + + // first check condition + if( ! checkObserved() ) + { + // add this as observer + for( i = observedProcesses_.begin(); i != observedProcesses_.end(); ++i ) + { + (*i)->data::Observable< base::ProcessObserver >::addObserver( this ); + } + } + else + { + ODEMX_TRACE << log( "continue" ) + .detail( "partner", waitCaller_->getLabel() ) + .scope( typeid(Wait) ); + + return true; + } + + // Wait for condition, block process execution + while( ! checkObserved() ) + { + waitCaller_->sleep(); + + // Handle interrupt + if( waitCaller_->isInterrupted() ) + { + // Remove this as observer + for( i = observedProcesses_.begin(); i != observedProcesses_.end(); ++i ) + { + (*i)->data::Observable< base::ProcessObserver >::removeObserver( this ); + } + + ODEMX_TRACE << log( "continue" ) + .detail( "partner", waitCaller_->getLabel() ) + .scope( typeid(Wait) ); + + return false; + } + } + // Condition fulfilled, block released + + // Remove this as observer + for( i = observedProcesses_.begin(); i != observedProcesses_.end(); ++i ) + { + (*i)->data::Observable<base::ProcessObserver>::removeObserver( this ); + } + + ODEMX_TRACE << log( "continue" ) + .detail( "partner", waitCaller_->getLabel() ) + .scope( typeid(Wait) ); + + return true; +} + +void Wait::initObservedList( size_t size, base::Process* p[] ) +{ + base::Process* proc = 0; + + // Add entries from p in observedProcesses_ + for( size_t i = 0; i < size; ++i ) + { + proc = p[i]; + + if( proc != 0 ) + { + addProcess( proc ); + } + } +} + +bool Wait::checkObserved() +{ + // Check Condition: one(all) observed process(es) TERMINATED + base::ProcessList::iterator i; + + if( waitForAll_ ) + { + for( i = observedProcesses_.begin(); i != observedProcesses_.end(); ++i ) + { + // return false if not all processes have terminated + if( (*i)->getProcessState() != base::Process::TERMINATED ) + { + return false; + } + } + return true; + } + else + { + for( i = observedProcesses_.begin(); i != observedProcesses_.end(); ++i ) + { + // return true if one of the observed processes has terminated + if( (*i)->getProcessState() == base::Process::TERMINATED ) + { + return true; + } + } + return false; + } +} + +} } // namespace odemx::sync + +#endif /* ODEMX_USE_OBSERVATION */ diff --git a/odemx-lite/src/synchronization/WaitQ.cpp b/odemx-lite/src/synchronization/WaitQ.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f845b822eb5d827af61502539633f1315fe64c6 --- /dev/null +++ b/odemx-lite/src/synchronization/WaitQ.cpp @@ -0,0 +1,486 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2002, 2004 Humboldt-Universitaet zu Berlin +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//---------------------------------------------------------------------------- +/** \file WaitQ.cpp + + \author Ralf Gerstenberger + + \date created at 2002/03/26 + + \brief Implementation of odemx::sync::WaitQ + + \sa WaitQ.h + + \since 1.0 +*/ + +#include <odemx/synchronization/WaitQ.h> +#include <odemx/base/Process.h> +#include <odemx/base/Sched.h> +#include <odemx/base/Simulation.h> + +#include <string> +#include <cassert> + +namespace odemx { +namespace synchronization { + +WaitQ::WaitQ( base::Simulation& sim, const data::Label& label, WaitQObserver* obs ) +: data::Producer( sim, label ) +, data::Observable< WaitQObserver >( obs ) +, masterQueue_( sim, getLabel() + ".master-queue" ) +, slaveQueue_( sim, getLabel() + ".slave-queue" ) +{ + ODEMX_TRACE << log( "create" ).scope( typeid(WaitQ) ); + + statistics << param( "master queue", masterQueue_.getLabel() ).scope( typeid(WaitQ) ); + statistics << param( "slave queue", slaveQueue_.getLabel() ).scope( typeid(WaitQ) ); + + // observer + ODEMX_OBS(WaitQObserver, Create(this)); +} + +WaitQ::~WaitQ() +{ + ODEMX_TRACE << log( "destroy" ).scope( typeid(WaitQ) ); +} + +bool WaitQ::wait() +{ + // WaitQ synchronization only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "WaitQ::wait(): called by non-Process object" ) + .scope( typeid(WaitQ) ); + return false; + } + + base::Process* slave = getCurrentProcess(); + + ODEMX_TRACE << log( "wait" ).detail( "slave", slave->getLabel() ).scope( typeid(WaitQ) ); + + // observer + ODEMX_OBS(WaitQObserver, Wait(this, slave)); + + // awake masters + awakeAll( &masterQueue_ ); + + // slave waits for master + slaveQueue_.inSort( slave ); + + // entrance time in queue is stored equal to execution time + // sleep + slave->sleep(); + + if( slave->isInterrupted() ) + { + slaveQueue_.remove( slave ); + return false; + } + + return true; +} + +bool WaitQ::wait( base::Weight weightFct ) +{ + // WaitQ synchronization only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "WaitQ::wait(): called by non-Process object" ) + .scope( typeid(WaitQ) ); + return false; + } + + base::Process* slave = getCurrentProcess(); + + ODEMX_TRACE << log( "wait weight" ).detail( "slave", slave->getLabel() ).scope( typeid(WaitQ) ); + + // observer + ODEMX_OBS(WaitQObserver, WaitWeight(this, slave)); + + if( ! masterQueue_.isEmpty() ) + { + // evaluate master weight function for this slave + base::ProcessList::const_iterator i = masterQueue_.getList().begin(); + base::ProcessList::const_iterator end = masterQueue_.getList().end(); + + // initialize max weighted master variable + base::Process* maxWeightMaster = *i; + // get weight of slave in relation to first master + double maxWeight = weightFct(maxWeightMaster, slave); + + // iterate over master queue to get the master + // where this slave's weight is highest + for( ++i; i != end; ++i ) + { + // get the slave's weight for the current master + double currentWeight = weightFct(*i, slave); + + // if current master's slave weight is highest so far, remember it + if( currentWeight > maxWeight ) + { + maxWeight = currentWeight; + maxWeightMaster = *i; + } + } + // awaken the master process with the highest weight evaluation + maxWeightMaster->activateAfter( slave ); + } + + // slave waits for master + slaveQueue_.inSort( slave ); + + // entrance time in queue is stored equal to execution time + // sleep + slave->sleep(); + + if( slave->isInterrupted() ) + { + slaveQueue_.remove( slave ); + return false; + } + + return true; +} + +base::Process* WaitQ::coopt( base::Weight weightFct ) +{ + // WaitQ synchronization only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "WaitQ::coopt(): called by non-Process object" ) + .scope( typeid(WaitQ) ); + return 0; + } + + base::Process* master = getCurrentProcess(); + base::Process* slave = getWeightedSlave( master, weightFct ); + + // no slave available + if( slave == 0 ) + { + ODEMX_TRACE << log( "coopt weight failed" ) + .detail( "master", master->getLabel() ) + .scope( typeid(WaitQ) ); + + // observer + ODEMX_OBS(WaitQObserver, CooptWeightFail(this, master)); + + // master is waiting for slave + masterQueue_.inSort( master ); + + // this master must wait + do + { + master->sleep(); + + if( master->isInterrupted() ) + { + masterQueue_.remove( master ); + return 0; + } + slave = getWeightedSlave( master, weightFct ); + } + while( slave == 0 ); + + // block released + + masterQueue_.remove( master ); + } + + // remove chosen slave from queue + slaveQueue_.remove( slave ); + + // statistics + updateStatistics( master, slave ); + + ODEMX_TRACE << log( "coopt weight succeeded" ) + .detail( "master", master->getLabel() ) + .detail( "slave", slave->getLabel() ) + .scope( typeid(WaitQ) ); + + // observer + ODEMX_OBS( WaitQObserver, CooptWeightSucceed( this, master, slave ) ) + + return slave; +} + +base::Process* WaitQ::coopt( base::Selection sel ) +{ + // WaitQ synchronization only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "WaitQ::coopt(): called by non-Process object" ) + .scope( typeid(WaitQ) ); + return 0; + } + + // attempt blocking synchronization + return sync( true, sel ); +} + +base::Process* WaitQ::avail( base::Selection sel ) +{ + // WaitQ synchronization only implemented for processes + if( ! getCurrentSched() || getCurrentSched()->getSchedType() != base::Sched::PROCESS ) + { + error << log( "WaitQ::avail(): called by non-Process object" ) + .scope( typeid(WaitQ) ); + + return 0; + } + + // attempt non-blocking synchronization + return sync( false, sel ); +} + +base::Process* WaitQ::sync( bool wait, base::Selection sel ) +{ + base::Process* master = getCurrentProcess(); + base::Process* slave = getSlave( master, sel ); + + if( slave == 0 ) + { + // trace + data::StringLiteral recordText; + if( wait ) + { + if( sel ) recordText = "coopt select failed"; + else recordText = "coopt failed"; + } + else + { + if( sel ) recordText = "avail select failed"; + else recordText = "avail failed"; + } + + ODEMX_TRACE << log( recordText ) + .detail( "master", master->getLabel() ) + .scope( typeid(WaitQ) ); + + // observer + if( wait ) // called from coopt() + { + if( sel == 0 ) + { + ODEMX_OBS(WaitQObserver, CooptFail(this, master)) + } + else + { + ODEMX_OBS(WaitQObserver, CooptSelFail(this, master)) + } + } + else // called from avail() + { + if( sel == 0 ) + { + ODEMX_OBS(WaitQObserver, AvailFail(this, master)) + } + else + { + ODEMX_OBS(WaitQObserver, AvailSelFail(this, master)) + } + } + + if( wait ) // called from coopt() + { + // master is waiting for slave + masterQueue_.inSort( master ); + + do + { + master->sleep(); + + if( master->isInterrupted() ) + { + masterQueue_.remove( master ); + return 0; + } + + slave = getSlave( master, sel ); + } + while( slave == 0 ); + + // block released + masterQueue_.remove( master ); + } + else // called from avail() + { + return 0; + } + } + + // get slave + slaveQueue_.remove( slave ); + + // statistics + updateStatistics( master, slave ); + + // trace + data::StringLiteral recordText; + if( wait ) + { + if( sel ) recordText = "coopt select succeeded"; + else recordText = "coopt succeeded"; + } + else + { + if( sel ) recordText = "avail select succeeded"; + else recordText = "avail succeeded"; + } + + ODEMX_TRACE << log( recordText ) + .detail( "master", master->getLabel() ) + .detail( "slave", slave->getLabel() ) + .scope( typeid(WaitQ) ); + + // observer + if( wait ) // called from coopt() + { + if( sel == 0 ) + { + ODEMX_OBS(WaitQObserver, CooptSucceed(this, master, slave)) + } + else + { + ODEMX_OBS(WaitQObserver, CooptSelSucceed(this, master, slave)) + } + } + else // called from avail() + { + if( sel == 0 ) + { + ODEMX_OBS(WaitQObserver, AvailSucceed(this, master, slave)) + } + else + { + ODEMX_OBS(WaitQObserver, AvailSelSucceed(this, master, slave)) + } + } + + return slave; +} + +base::Process* WaitQ::getSlave( base::Process* master, base::Selection sel ) +{ + if( slaveQueue_.isEmpty() || ( master == 0 ) ) + { + return 0; + } + + if( sel == 0 ) + { + return slaveQueue_.getTop(); + } + + base::ProcessList::const_iterator i; + base::ProcessList::const_iterator end = slaveQueue_.getList().end(); + + for( i = slaveQueue_.getList().begin(); i != end; ++i ) + { + // check if current slave fits the selection + if( sel(master, *i) ) + { + return *i; + } + } + + return 0; +} + +base::Process* WaitQ::getWeightedSlave( base::Process* master, base::Weight weightFct ) +{ + // nothing to synchronize + if( slaveQueue_.isEmpty() || ( master == 0 ) ) + { + return 0; + } + + // no weight to evaluate, take first in queue + if( weightFct == 0 ) + { + return slaveQueue_.getTop(); + } + + // evaluate master weight function + base::ProcessList::const_iterator i = slaveQueue_.getList().begin(); + base::ProcessList::const_iterator end = slaveQueue_.getList().end(); + + // initialize max weighted slave variable + base::Process* maxWeightSlave = *i; + // get weight of first slave + double maxWeight = weightFct (master, maxWeightSlave); + + // iterate over slave queue to get the maximum weighted slave + for( ++i; i != end; ++i ) + { + // get the current slave's weight + double currentWeight = weightFct(master, *i); + + // if current slave's weight is highest so far, remember it + if( currentWeight > maxWeight ) + { + maxWeight = currentWeight; + maxWeightSlave = *i; + } + } + + return maxWeightSlave; +} + +const base::ProcessList& WaitQ::getWaitingSlaves() const +{ + return slaveQueue_.getList(); +} + +const base::ProcessList& WaitQ::getWaitingMasters() const +{ + return masterQueue_.getList(); +} + +void WaitQ::updateStatistics( base::Process* master, base::Process* slave) +{ + assert( master && slave ); + + // master and slave synchronized (served) + statistics << count( "synchronizations" ).scope( typeid(WaitQ) ); + + // calculate waiting times + base::SimTime masterWaitTime = master->getDequeueTime() - master->getEnqueueTime(); + base::SimTime slaveWaitTime = slave->getDequeueTime() - slave->getEnqueueTime(); + + statistics << update( "master wait time", masterWaitTime ).scope( typeid(WaitQ) ); + statistics << update( "slave wait time", slaveWaitTime ).scope( typeid(WaitQ) ); +} + +base::SimTime WaitQ::getTime() const +{ + return getSimulation().getTime(); +} + +base::Sched* WaitQ::getCurrentSched() +{ + return getSimulation().getCurrentSched(); +} + +base::Process* WaitQ::getCurrentProcess() +{ + return getSimulation().getCurrentProcess(); +} + +} } // namespace odemx::sync