diff --git a/cmake/modules/FindClangFormat.cmake b/cmake/modules/FindClangFormat.cmake index ba19d37..157458b 100755 --- a/cmake/modules/FindClangFormat.cmake +++ b/cmake/modules/FindClangFormat.cmake @@ -1,22 +1,29 @@ # CMake find_package() Module for clang-format # # Example usage: # # find_package(ClangFormat) # # If successful the following variables will be defined # CLANGFORMAT_FOUND # CLANGFORMAT_EXECUTABLE -find_program(CLANGFORMAT_EXECUTABLE - NAMES clang-format - PATHS ${ROSA_CLANG_FORMAT_PATH} - DOC "Path to clang-format executable") +if( ROSA_CLANG_FORMAT_PATH STREQUAL "" ) + find_program(CLANGFORMAT_EXECUTABLE + NAMES clang-format + DOC "Path to clang-format executable") +else() + find_program(CLANGFORMAT_EXECUTABLE + NAMES clang-format + PATHS ${ROSA_CLANG_FORMAT_PATH} + DOC "Path to clang-format executable" + NO_DEFAULT_PATH) +endif() # Handle REQUIRED and QUIET arguments # this will also set CLANGFORMAT_FOUND to true if CLANGFORMAT_EXECUTABLE exists include(FindPackageHandleStandardArgs) find_package_handle_standard_args(ClangFormat "Failed to locate clang-format executable" CLANGFORMAT_EXECUTABLE) diff --git a/cmake/modules/FindClangTidy.cmake b/cmake/modules/FindClangTidy.cmake index 05702ac..3e53599 100755 --- a/cmake/modules/FindClangTidy.cmake +++ b/cmake/modules/FindClangTidy.cmake @@ -1,22 +1,29 @@ # CMake find_package() Module for clang-tidy # # Example usage: # # find_package(ClangTidy) # # If successful the following variables will be defined # CLANGTIDY_FOUND # CLANGTIDY_EXECUTABLE -find_program(CLANGTIDY_EXECUTABLE - NAMES clang-tidy - PATHS ${ROSA_CLANG_TIDY_PATH} - DOC "Path to clang-tidy executable") +if( ROSA_CLANG_TIDY_PATH STREQUAL "" ) + find_program(CLANGTIDY_EXECUTABLE + NAMES clang-tidy + DOC "Path to clang-tidy executable") +else() + find_program(CLANGTIDY_EXECUTABLE + NAMES clang-tidy + PATHS ${ROSA_CLANG_TIDY_PATH} + DOC "Path to clang-tidy executable" + NO_DEFAULT_PATH) +endif() # Handle REQUIRED and QUIET arguments # this will also set CLANGTIDY_FOUND to true if CLANGTIDY_EXECUTABLE exists include(FindPackageHandleStandardArgs) find_package_handle_standard_args(ClangTidy "Failed to locate clang-tidy executable" CLANGTIDY_EXECUTABLE) diff --git a/cmake/modules/HandleROSAOptions.cmake b/cmake/modules/HandleROSAOptions.cmake index ad04f21..6571163 100644 --- a/cmake/modules/HandleROSAOptions.cmake +++ b/cmake/modules/HandleROSAOptions.cmake @@ -1,102 +1,102 @@ # This CMake module is responsible for interpreting the user defined ROSA_ # options and executing the appropriate CMake commands to realize the users' # selections. include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) if( CMAKE_COMPILER_IS_GNUCXX ) set(ROSA_COMPILER_IS_GCC_COMPATIBLE ON) elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) set(ROSA_COMPILER_IS_GCC_COMPATIBLE ON) elseif( MSVC ) set(ROSA_COMPILER_IS_GCC_COMPATIBLE OFF) endif() function(append value) foreach(variable ${ARGN}) set(${variable} "${${variable}} ${value}" PARENT_SCOPE) endforeach(variable) endfunction() function(append_if condition value) if (${condition}) foreach(variable ${ARGN}) set(${variable} "${${variable}} ${value}" PARENT_SCOPE) endforeach(variable) endif() endfunction() # NDEBUG on non-Debug builds append("-DNDEBUG" CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL) # Assertions are always enabled on Debug builds, this is interesting for # non-Debug builds. if( NOT "${uppercase_CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" AND ${ROSA_ENABLE_ASSERTIONS} ) # MSVC doesn't like _DEBUG on release builds. See PR 4379. if( NOT MSVC ) add_definitions( -D_DEBUG ) set(ENABLE_ASSERTIONS "1") else() set(ENABLE_ASSERTIONS "0") endif() # On non-Debug builds we NDEBUG, but in this case we need to undefine it: add_definitions(-UNDEBUG) # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines. foreach (flags_var_to_scrub CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL) string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " "${flags_var_to_scrub}" "${${flags_var_to_scrub}}") endforeach() endif() set(ROSA_ENABLE_ASSERTIONS_INT -1) if( "${uppercase_CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" OR ${ROSA_ENABLE_ASSERTIONS} ) set(ROSA_ENABLE_ASSERTIONS_INT 1) endif() -#FIXME: Disable RTTI and exceptions, once gen_agent_test2 is cleared up. - if( ROSA_COMPILER_IS_GCC_COMPATIBLE ) append("-Wall -Wextra -Wdocumentation -Werror" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) append_if(ROSA_ENABLE_PEDANTIC "-pedantic -Wno-long-long" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + append("-fno-rtti -fno-exceptions" CMAKE_CXX_FLAGS) + check_cxx_compiler_flag("-std=c++14" CXX_SUPPORTS_CXX14) if ( CXX_SUPPORTS_CXX14 ) append("-std=c++14" CMAKE_CXX_FLAGS) else() message(FATAL_ERROR "RoSA requires C++14 support but the '-std=c++14' flag isn't supported.") endif() check_c_compiler_flag("-std=c11" C_SUPPORTS_C11) if ( C_SUPPORTS_C11 ) append("-std=c11" CMAKE_C_FLAGS) else() message(FATAL_ERROR "RoSA requires C11 support but the '-std=c11' flag isn't supported.") endif() else ( ROSA_COMPILER_IS_GCC_COMPATIBLE ) # FIXME: set the same things as for GCC-compatible compilers endif( ROSA_COMPILER_IS_GCC_COMPATIBLE ) if( ROSA_ENABLE_CLANG_TIDY ) # Set clang-tidy arguments, use the same for both C and CXX. set(CMAKE_C_CLANG_TIDY "${CLANGTIDY_EXECUTABLE};-header-filter=.*") set(CMAKE_CXX_CLANG_TIDY ${CMAKE_C_CLANG_TIDY}) # Apply suggested fixes if requested. append_if(ROSA_CLANG_TIDY_FIX ",-fix" CMAKE_C_CLANG_TIDY CMAKE_CXX_CLANG_TIDY) endif( ROSA_ENABLE_CLANG_TIDY ) diff --git a/docs/Build.rst b/docs/Build.rst index 9a06315..1110d85 100755 --- a/docs/Build.rst +++ b/docs/Build.rst @@ -1,343 +1,348 @@ =========================== Building the RoSA Framework =========================== .. contents:: :local: Build Dependencies ================== In order to build RoSA, the following tools are required: * `CMake `_ (minimum version 3.6.0 if clang-tidy is used, 2.8.8 otherwise); * Build system of your choice that can be targeted by CMake -- including a compiler supporting *C++14*. + * LLVM -- minimum version 3.9.0 (due to :ref:`this issue + `) + The following additional tools are required to generate documentation: * `Doxygen `_ -- for generating API documentation; * `Graphviz `_ -- not necessary, but the API documentation has nicer graphics when `dot` is available; * `Sphinx `_ (with *Python 2*) -- for generating documentation. The following additional tools are required to check and possibly enforce coding standard: * `clang-tidy `_ * `clang-format `_ General notes ============= * The framework is delivered with a CMake project, which can be used to generate build projects to build the framework. * The provided CMake project supports out-of-tree builds only, i.e. one must use a separate build directory outside of the RoSA source directory. .. _cmake-variables: CMake Variables =============== Beyond the usual CMake variables, the following project-related options are available: `ROSA_INCLUDE_TOOLS` Generate build targets for RoSA tools. The tools are also built when the option is set to `ON`, which is the default setting. `ROSA_INCLUDE_EXAMPLES` Generate build targets for RoSA examples. The examples are also built when the option is set to `ON`, which is the default setting. `ROSA_ENABLE_PEDANTIC` Compile the framework with using `-pedantic`. The option defaults to `ON`. `ROSA_ENABLE_ASSERTIONS` Enable assertions for non-Debug builds, which defaults to `OFF`. Note that assertions are always enabled for Debug builds and this option is ignored for such builds. .. _CMake_clang_tidy: `ROSA_ENABLE_CLANG_TIDY` Run *clang-tidy* checks when building RoSA, which defaults to `OFF`. When the variable is enabled, build targets created by *Makefile* and *Ninja* generators include calls for clang-tidy. Other generators ignore this option. Note that CMake variables `CMAKE__CLANG_TIDY` are set when enabled. Settings for clang-tidy are defined by the file `.clang-tidy` in the RoSA source directory. Consider the following options when the option is enabled: `ROSA_CLANG_TIDY_PATH` Custom path for `clang-tidy` executable. - In order to use clang-tidy, CMake needs to find the `clang-tidy` executable. - If `clang-tidy` is available via `PATH`, just leave the option empty - -- which is default. Set the absolute path of the directory containing the - `clang-tidy` executable otherwise. + In order to use clang-tidy, CMake needs to find the `clang-tidy` + executable. If `clang-tidy` to be used is available via `PATH`, just leave + the option empty -- which is default. Set the absolute path of the + directory containing the `clang-tidy` executable otherwise, in which case + no default path is searched for `clang-tidy`. `ROSA_CLANG_TIDY_FIX` Apply suggested clang-tidy fixes to the sources, which defaults to `OFF`. Enable the option only if you know what you are doing. .. _CMake_clang_format: `ROSA_INCLUDE_CLANG_FORMAT` **[experimental]** Generate build target -- `format-rosa` -- for formatting RoSA sources with *clang-format*, which defatuls to `OFF`. When the variable is enabled and *CMake is not running on a Windows host*, a build target is generated which can be used to have all the RoSA sources formatted with clang-format. Settings for clang-format are defined by the file `.clang-format` in the RoSA source directory. Note that executing build target `format-rosa` will reformat all the source files *inplace*. Consider the following option when a build target for clang-format is to be generated: `ROSA_CLANG_FORMAT_PATH` Custom path for `clang-format` executable. In order to use clang-format, CMake needs to find the `clang-format` - executable. If `clang-format` is available via `PATH`, just leave the option - empty -- which is default. Set the absolute path of the directory containing - the `clang-format` executable otherwise. + executable. If `clang-format` to be used is available via `PATH`, just + leave the option empty -- which is default. Set the absolute path of the + directory containing the `clang-format` executable otherwise, in which case + no default path is search for `clang-format`. `ROSA_LOG_LEVEL` Level of logging to be used, use one of the following valid integer values. ======== ========= Variable Log Level ======== ========= `0` `ERROR` `1` `WARNING` `2` `INFO` `3` `DEBUG` `4` `TRACE` `5` *disabled* ======== ========= Level of logging defaults to *disabled*. `ROSA_INCLUDE_DOCS` Generate build targets for RoSA documentation, defaults to `ON`. Note that the automatic execution of the generated build targets is controlled by the option `ROSA_BUILD_DOCS`. The actual documentations to build are controlled by the options `ROSA_ENABLE_DOXYGEN` and `ROSA_ENABLE_SPHINX`. `ROSA_BUILD_DOCS` Build RoSA documentation automatically as part of the build process. The option defaults to `OFF` and takes effect only if the option `ROSA_INCLUDE_DOCS` is enabled. .. _CMake_doxygen: `ROSA_ENABLE_DOXYGEN` Use *doxygen* to generate RoSA API documentation. The option defaults to `OFF` and takes effect only if the option `ROSA_INCLUDE_DOCS` is enabled. Doxygen documentation may be generated by executing build target `doxygen-rosa`, which is done as part of the default build process if `ROSA_BUILD_DOCS` is enabled. Doxygen must be available via `PATH` if the option is enabled. The following options are also available to tune doxygen: `ROSA_DOXYGEN_SVG` Use *svg* instead of *png* files for doxygen graphs. The option defaults to `OFF` and takes effect if the tool *dot* is available via `PATH` to be used to generated graph images. `ROSA_DOXYGEN_EXTERNAL_SEARCH` Enable doxygen external search, which defatuls to `OFF`. The following options need to be set if the option is enabled: `ROSA_DOXYGEN_SEARCHENGINE_URL` URL to use for external search. `ROSA_DOXYGEN_SEARCH_MAPPINGS` Doxygen Search Mappings. .. _CMake_sphinx: `ROSA_ENABLE_SPHINX` Use *Sphinx* to generate RoSA documentation. The option defaults to `OFF` and takes effect only if the option `ROSA_INCLUDE_DOCS` is enabled. Sphinx must be available via `PATH` if the option is enabled. The following options are also available to tune Sphinx: `SPHINX_OUTPUT_HTML` Output standalone HTML files. The option defaults to `ON`. Documentation may be generated by executing build target `docs-rosa-html`, which is done as part of the default build process if `ROSA_BUILD_DOCS` is enabled. `SPHINX_OUTPUT_MAN` Output man pages for RoSA tools. The option defaults to `ON`. Man pages may be generated by executing build target `docs-rosa-man`, which is done as part of the default build process if `ROSA_BUILD_DOCS` is enabled. `SPHINX_WARNINGS_AS_ERRORS` When building documentation, treat Sphinx warnings as errors. The option defaults to `ON`. Building RoSA Step-by-Step ========================== Building on Linux with Make --------------------------- Configuring and building the framework on Linux using *Make* is a straightforward process which does not require performing any tricks. The framework compiles with *Clang 3.8.0*. Set C and C++ compilers with the variables `CC` and `CXX`, respectively. Use the CMake variable `CMAKE_BUILD_TYPE` to set the type of build: `Debug`, `Release`. Follows an example on building the framework. You need to have RoSA sources on your computer and Clang executables available via `PATH`.:: rosa-src$ cd .. $ mkdir rosa-build $ cd rosa-build rosa-build$ CC=clang CXX=clang++ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DROSA_LOG_LEVEL=4 ../rosa-src/ [CMake configures and generates without errors] $ make [Make builds the project] You just need to re-run Make in order to re-build the project after changing the source code and the CMake project. In case the CMake project is changed, Make automatically calls CMake to update the build project. In order to build documentation and enforce coding standard, refer to corresponding :ref:`cmake-variables`. .. _Build_VS: Building on Windows with Visual Studio -------------------------------------- Unfortunately, the native MSVC compiler cannot compile the framework. One needs to use Clang with Visual Studio in order to build the framework. There are two alternatives to do that: * using the *Clang/C2* module for *Visual Studio 2017*, * using *LLVM for Windows* as an external toolset for Visual Studio (necessary for older versions of Visual Studio). For using Visual Studio 2017 -- which would be the preferred way -- one needs to select *Clang/C2 (experimental)* on the *Individual components* tab in *Visual Studio Installer*. For using *LLVM for Windows*, one downloads the official binary release from http://llvm.org and consults with its documentation. The release provides integration for Visual Studio versions between 2010 and 2014 (as of LLVM 4.0.0). Having your build system prepared and RoSA sources fetched to your computer, configure and build the framework like this: #. Generate Visual Studio solution with CMake: #. Start CMake. #. Define *source directory* and a separate *build directory* in CMake. #. Click *Configure*. #. Select the proper *generator* for your version of Visual Studio. #. Define your optional toolset (argument for `-T`): * Clang/C2 with VS2017: `v141_clang_c2`. * LLVM for Windows with older VS: `LLVM-vs`. #. Click *Finish*. #. Tune CMake variables as you wish. * Note that Visual Studio Generators are multi-configuration generators, hence you cannot set `CMAKE_BUILD_TYPE`. You need to select a configuration to build in Visual Studio. #. Click *Generate*. .. _CMake-VS2017-Clang-fix: #. Fix the generated Visual Studio projects (*applies for Clang/C2*): * The generated projects define `ExceptionHandling` as `Sync`, which is an invalid value for Clang/C2 and needs to be changed to `Enabled` in all Visual Studio project files: * using GNU command line tools:: rosa-build$ find . -name "*.vcxproj" -print|xargs sed -i -e 's/Sync/Enabled/g' * using PowerShell:: rosa-build> ls -path . -include *.vcxproj -recurse | %{ $f=$_; (gc $f.PSPath) | %{ $_ -replace "Sync", "Enabled" } | sc $f.PSPath } * Note that the project files need to be fixed every time CMake regenerates them, which may happen when building the project in Visual Studio in case you have the CMake project changed in the source directory. #. Build the framework with Visual Studio: #. Open the generated `RoSA.sln` from the build directory with Visual Studio. #. Build the project `ALL_BUILD`. You just need to re-build the project in Visual Studio after changing the source code and the CMake project. In case the CMake project is changed, Visual Studio automatically calls CMake the update the build project. Should you use Clang/C2, do not forget to :ref:`fix the generated Visual Studio projects `. Build Result ============ The build process works in the build directory. After a successful build, one can find the following final outputs there -- besides some intermediate files. .. _Build_Result_Software: Software -------- In the build directory, `include` contains header files which are generated by CMake and provide configuration-specific information. The build process generates static libraries in `lib` and executables -- examples and tools -- in `bin`. Projects generated by a multi-configuration generator result in the actual libraries and executables being located in subdirectories corresponding to different build configurations. .. _Build_Result_Documentation: Documentation ------------- Documentation is generated in `docs`. The general documentation can be found in `docs/html`. Man pages for tools can be found in `docs/man`. The API documentation can be found in `docs/doxygen/html`. diff --git a/docs/Dev.rst b/docs/Dev.rst index 56581df..dbe5980 100755 --- a/docs/Dev.rst +++ b/docs/Dev.rst @@ -1,344 +1,353 @@ ============================= Developing the RoSA Framework ============================= .. contents:: :local: This document provides information that might be useful for contributing to RoSA. Please also consult :doc:`Build`. .. _Dev_Source_Directory: The Source Directory ==================== The source directory consists of the following subdirectories: `cmake` Contains files used for configuring the `CMake Project`_. `docs` Contains `Documentation`_-related files. `examples` Contains `Examples`_ on using the public API. `include/rosa` Contains the RoSA public API -- that is the interface of RoSA `Libraries`_. The directory `include` is to be used as include directory and RoSA header files are to be included in C++ sources as `"rosa/"`. `lib` Contains the implementation of the RoSA public API -- that is the implementation of RoSA `Libraries`_. `tools` Contains `Tools`_ based on RoSA features. Software Sources ================ The section describes the `Logical Structure`_ of the software sources and what `Coding Standards`_ are supposed to be followed for the implementation. Logical Structure ----------------- Various features provided by RoSA are sorted into different `Libraries`_. `Examples`_ and `Tools`_ using those `Libraries`_ are separated from the implementation of the RoSA features into different directories. Libraries ~~~~~~~~~ The framework consists of separate libraries providing different features. The public interfaces for RoSA libraries are defined in `include/rosa`, while corresponding implementation is in `lib`. Each library has its own subdirectory in the mentioned directories. RoSA provides the following libraries: `config` Provides information on the configuration used to build the framework, e.g., version number, log level, assertions, and debugging. `support` Provides general features -- template metaprograms dealing with types, for instance -- for implementing other libraries. `core` Provides the basic RoSA features, like systems managing agents passing messages. `agent` Provides features to be used for implementing agents. .. _Library_Dependencies: Dependencies '''''''''''' The following table summarizes dependencies among libraries. A marking in a row denotes that the library in the beginning of the row depends on the library in the head of the given column. -+---------+--------+---------+------+-------+ -| | config | support | core | agent | -+=========+========+=========+======+=======+ -| config | | | | | -+---------+--------+---------+------+-------+ -| support | | | | | -+---------+--------+---------+------+-------+ -| core | | × | | | -+---------+--------+---------+------+-------+ -| agent | | | | | -+---------+--------+---------+------+-------+ ++---------+--------+---------+------+--------+-------+ +| | config | support | core | deluxe | agent | ++=========+========+=========+======+========+=======+ +| config | | | | | | ++---------+--------+---------+------+--------+-------+ +| support | | | | | | ++---------+--------+---------+------+--------+-------+ +| core | | × | | | | ++---------+--------+---------+------+--------+-------+ +| deluxe | | | × | | | ++---------+--------+---------+------+--------+-------+ +| agent | | | | | | ++---------+--------+---------+------+--------+-------+ Examples ~~~~~~~~ Some simple samples are provided in `examples` to demonstrate how to to use different parts of the RoSA API. Tools ~~~~~ Tools, programs based on the RoSA libraries, are implemented in `tools`. .. _Coding_Standards: Coding Standards ---------------- RoSA is implemented in standard *C++14* code. All the software sources are to be written in accordance to the `LLVM Coding Standards`_. +Feature Restrictions +~~~~~~~~~~~~~~~~~~~~ + +Pay attention `not to use RTTI and Exceptions`_. Those features are disabled in +the CMake project. + Documentation Comments ~~~~~~~~~~~~~~~~~~~~~~ It is important to remember to document source code using `doxygen comments`_ as `API Documentation`_ is generated directly from sources. Note that the syntax of documentation comments is checked during compilation -- at least when using a GCC-compatible compiler. Whenever you work on a source file, make sure your name is in the author-list defined in the header comment of the file. Each author should be defined with a separate `\\author` command so that recent authors come first. Authors not participating in further development of a file anymore may be marked with the period of their contribution. If declarations belonging to a namespace are spread to more than one source files, document the namespace in a separate `namespace.h` in the directory belonging to the library. Otherwise, document the namespace in the only file in which entities of the namespace are declared. Header Files ~~~~~~~~~~~~ Follow the recommendations on public and private header files and the usage of `#include` from the `LLVM Coding Standards`_. Use `.h` and `.hpp` extensions to indicate the content of the header file: * header files containing any *definition* -- template or inline definition -- or including another header file with `.hpp` extension have `.hpp` extension; * header files containing only *declarations* and including only header files with `.h` extension have `.h` extension. It may happen that a header file does not need any corresponding implementation in a `.cpp` file. Nevertheless, do create a corresponding `.cpp` file which only includes the header file in this case. That makes sure that the header file is compiled and hence checked for errors, and also a corresponding entry in the compilation database is generated. Checking and Enforcing the Coding Standards ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The tools `clang-tidy `_ and `clang-format `_ can be used to check and enforce the coding standards. The two tools are integrated into the CMake project, refer to CMake variables :ref:`ROSA_ENABLE_CLANG_TIDY ` and :ref:`ROSA_INCLUDE_CLANG_FORMAT `. Note that there may be situations when `clang-tidy` checks result in false positives -- for example, for some cases of the order of `#include` directives. One can order `clang-tidy` to suppress warnings for a line of code by marking that line with:: // NOLINT It may be preferred to diverge from the standard formatting -- for example for the sake of readability of static definition of arrays following some structure. One can disable `clang-format` for some lines of code by designating a range with two special comments as:: // clang-format off ... clang-format is disabled here ... // clang-format on Documentation ============= The RoSA Framework is delivered with two kinds of documentation: `General Documentation`_ and `API Documentation`_, generation of both of which is integrated into the CMake project. References between the two documentations are relative addresses corresponding to the directory structure of the :ref:`generated documentation `. General Documentation --------------------- General documentation is written as `reStructuredText `_ compiled with `Sphinx `_. For build integration, refer to the CMake variable :ref:`ROSA_ENABLE_SPHINX `. Documentation files are located in `docs` with extension `.rst`. The main page of the documentation is `docs/index.rst`. Configuration for building the documentation is `docs/conf.py`. The directory `docs/CommandGuide` contains documentation for each separate tool. Those pages are included in the HTML documentation via `docs/CommandGuide/index.rst`. Moreover, man pages can be generated from those tool documentation pages. API Documentation ----------------- API documentation is directly generated from sources with `Doxygen `_. For build integration, refer to the CMake variable :ref:`ROSA_ENABLE_DOXYGEN `. The main page used for the API documentation is `docs/doxygen-mainpage.dox`. Configuration for generating the API documentation is `docs/doxygen.cfg.in`. .. _CMake Project: Managing the CMake Project ========================== This section briefly summarizes when and how to modify CMake files during the development process. No general discussion on CMake features is provided here. When modifying `Documentation`_, no need to update the CMake files. Software -------- One needs to modify the CMake files only if source files are to be added or removed from the project. Here follows some typical scenarios. Source Files ~~~~~~~~~~~~ Each library and executable target has its own directory and its own definition as a file called `CMakeLists.txt` in that directory. When adding or removing a source file -- both headers and `.cpp` files -- to a library or executable, locate the corresponding `CMakeLists.txt` file. The file is typically in the same directory where the file to be added or removed is located. Except for header files of the public API, for which the corresponding CMake target is defined in a `lib` subdirectory corresponding to the library the header files belongs to. Update the source list in the argument of the `add_library` or `add_executable` command in the `CMakeLists.txt`, for libraries and executables, respectively. A library and executable may use features provided by another library. Such a dependency is to be defined in the `CMakeLists.txt` file of the dependent target by using the `ROSA_add_library_dependencies` command. CMake Libraries ~~~~~~~~~~~~~~~ When adding or removing a library, add or remove the corresponding directories from `include` and `lib`, and also update `lib/CMakeLists.txt` by adding or removing a `add_subdirectory` command for the library. When defining a new library, the new subdirectory under `lib` needs to contain a `CMakeLists.txt`, which needs to contain at least an `add_library` command defining the name of the library and the source files belonging to it. CMake Executables ~~~~~~~~~~~~~~~~~ When adding or removing an executable, add or remove the corresponding directory from `examples` or `tools`, and also update `CMakeLists.txt` in the containing directory as for libraries. When defining a new executable, the new subdirectory needs to contain a `CMakeLists.txt`, which needs to contain at least an `add_executable` command defining the name of the executable and the source files belonging to it. .. _Dev Managing Sources: Managing Sources ================ Consider the followings before committing changes to the repository: * your code complies with the `Coding Standards`_ as much as possible; * your code is well documented; * your code is not bloated with unusued code and/or comments; * your changes do not break building and executing the framework: * test all of the supported platforms if possible, * look into the generated documentation if you have edited `General Documentation`_; * you do not pollute the repository with unused and generated files. When committing changes to the repository, provide a concise log message with your commit. Miscellaneous Concerns ====================== Using YCM --------- If you happen to use `YCM `_, just make a copy of the provided `ycm_extra_conf.py.template` file as `.ycm_extra_conf.py` in the RoSA source directory, and set the following two variables in it: `compilation_database_folder` the absolute path of your build directory `extra_system_include_dirs` any system include directory which might not be searched by `libclang` [1]_. You probably want compile with Clang if you use YCM, so run CMake with environment variables `CC=clang` and `CXX=clang++` set. Also note that header files in the `include` directory are compiled for YCM with the compiler flags of a corresponding source file in the `lib` directory, if any. Header files in other locations are supposed to have a corresponding source file in the same directory. Notes ~~~~~ * If the project's include directory (`include/rosa`) would ever be changed, then the YCM configuration file needs to be adjusted accordingly. ---- .. [1] See: https://github.com/Valloric/YouCompleteMe/issues/303; use the following command to figure out the used system directories: echo | clang -std=c++11 -v -E -x c++ - .. _`LLVM Coding Standards`: http://llvm.org/docs/CodingStandards.html +.. _`not to use RTTI and Exceptions`: http://llvm.org/docs/CodingStandards.html#do-not-use-rtti-or-exceptions .. _`doxygen comments`: http://llvm.org/docs/CodingStandards.html#doxygen-use-in-documentation-comments diff --git a/docs/Issues.rst b/docs/Issues.rst index b2cf67f..c8c8f16 100755 --- a/docs/Issues.rst +++ b/docs/Issues.rst @@ -1,32 +1,37 @@ ================================================================== Known Issues with the Current Implementation of the RoSA Framework ================================================================== .. contents:: :local: TODO ==== * Project logo - `docs/_themes/rosa-theme/static/logo.png` * License? * Packaging with `CPack `_. * What about design documentation on the basics of RoSA? * What about testing the framework? Known Issues ============ * CMake * VS2017 generates intermediate files for the `ZERO_CHECK` project out of the build directory, see `CMake issue #16458`_. * VS2017 with `v141_clang_c2` toolset requires :ref:`fix of the generated Visual Studio projects `. -* clang-format +* clang - * `include/rosa/core/Message.hpp` breaks clang-format as of version 3.8.0. + .. _Issues_clang_template_argument_deduction_DeluxeAgent: + + * Clang breaks on template argument deduction when instantiating the class + `rosa::deluxe::DeluxeAgent`, the issue is gone with clang version 3.9.0 and + newer. Check the documentation on the relevant constructor for more + details. .. _CMake issue #16458: https://gitlab.kitware.com/cmake/cmake/issues/16458 diff --git a/examples/type-facilities/type-facilities.cpp b/examples/type-facilities/type-facilities.cpp index 44b7379..665a0ce 100644 --- a/examples/type-facilities/type-facilities.cpp +++ b/examples/type-facilities/type-facilities.cpp @@ -1,90 +1,90 @@ //===-- examples/type-facilities/type-facilities.cpp ------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/type-facilities/type-facilities.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief An example showcasing various type-related support facilities. /// //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include "rosa/support/type_token.hpp" #include using namespace rosa; using namespace rosa::terminal; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "type facilities" << Color::Default << '\n'; auto &Log = LOG_TRACE_STREAM; Log << "\nNumberOfBuiltinTypes: " << NumberOfBuiltinTypes << "\nTokenBits: " << token::TokenBits << "\nRepresentationBits: " << token::RepresentationBits << "\nMaxTokenizableListSize: " << token::MaxTokenizableListSize << "\n\n"; Log << "Type number information on 'uint8_t':"; constexpr TypeNumber TN = TypeNumberOf::Value; Log << "\n type number: " << PRINTABLE_TN(TN) << "\n size: " << TypeForNumber::Size << "\n name: " << TypeForNumber::Name << "\n\n"; Log << "Type number information on 'std::string':"; constexpr TypeNumber TNS = TypeNumberOf::Value; Log << "\n type number: " << PRINTABLE_TN(TNS) << "\n size: " << TypeForNumber::Size << "\n name: " << TypeForNumber::Name << "\n\n"; Log << "Type number information of AtomConstants:"; using Atom1 = AtomConstant; using Atom2 = AtomConstant; Log << "\n std::is_same::value: " << std::is_same::value << "\n TypeNumberOf::Value: " << PRINTABLE_TN(TypeNumberOf::Value) << "\n TypeNumberOf::Value: " << PRINTABLE_TN(TypeNumberOf::Value) << "\n name: " << TypeForNumber::Value>::Name << "\n\n"; Log << "Type token information on 'TypeList':"; // \c rosa::Token is generated statically. constexpr Token T = TypeToken::Value; STATIC_ASSERT( (T == TypeListToken>::Value), "alias template definition is wrong"); Token T_ = T; // We need a non-const value for dropping head later. // Iterate over encoded entries in \c T_. while (!emptyToken(T_)) { Log << "\n token: " << PRINTABLE_TOKEN(T_) << "\n valid: " << validToken(T_) << "\n empty: " << emptyToken(T_) << "\n length: " << lengthOfToken(T_) << "\n full size: " << sizeOfValuesOfToken(T_) - << "\n head type number: " << PRINTABLE_TN(typeNumberOfHeadOfToken(T_)) + << "\n head type number: " << PRINTABLE_TN(headOfToken(T_)) << "\n size of head: " << sizeOfHeadOfToken(T_) << "\n name of head: " << nameOfHeadOfToken(T_) << "\n is head uint8_t: " << isHeadOfTokenTheSameType(T_) << "\n is head uint16_t: " << isHeadOfTokenTheSameType(T_) << "\n is head std::string: " << isHeadOfTokenTheSameType(T_) << "\nDropping head..."; dropHeadOfToken(T_); } // Here when Token became empty. Log << "\n token: " << PRINTABLE_TOKEN(T_) << "\n empty: " << emptyToken(T_) << '\n'; return 0; } diff --git a/include/rosa/core/Agent.hpp b/include/rosa/core/Agent.hpp index eebe905..344b8f6 100644 --- a/include/rosa/core/Agent.hpp +++ b/include/rosa/core/Agent.hpp @@ -1,112 +1,137 @@ //===-- rosa/core/Agent.hpp -------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Agent.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of the base \c rosa::Agent class. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_AGENT_HPP #define ROSA_CORE_AGENT_HPP #include "rosa/core/AgentHandle.hpp" #include "rosa/core/MessageHandler.hpp" #include "rosa/core/MessagingSystem.hpp" #include "rosa/core/Unit.h" #include "rosa/support/log.h" namespace rosa { /// Implements an *Agent* that is a special \c rosa::Unit owned by a /// \c rosa::MessagingSystem, capable of handling \c rosa::Message instances /// as \c rosa::MessageHandler, and provides the \c rosa::AbstractAgent /// interface with \c rosa::AgentHandle as reference type. class Agent : public Unit, public MessageHandler, public AbstractAgent { friend class AgentHandle; ///< \c rosa::AgentHandle is our friend. protected: /// A handle for \p this object. const AgentHandle Self; public: /// Creates a new instance by instantiating all the base-classes. /// /// \tparam Fun type of the first mandatory function for handling messages /// \tparam Funs types of any further functions for handling messages /// /// \param Kind kind of the new \c rosa::Unit instance /// \param Id unique identifier of the new \c rosa::Unit instance /// \param Name name of the new \c rosa::Unit instance /// \param S \c rosa::MessagingSystem owning the new instance /// \param F the first mandatory function for handling messages /// \param Fs optional further functions for handling messages template Agent(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, Fun &&F, Funs &&... Fs); /// Destroys \p this object. ~Agent(void); /// Tells if \p this object is in a valid state. /// /// \note A \c rosa::Agent instance is always valid. /// /// \return if \p this object is in a valid state operator bool(void) const noexcept override; /// Tells if a given reference refers to \p this object. /// /// \param H reference to another object /// /// \return if \p H refers to \p this object bool operator==(const AgentHandle &H) const noexcept override; /// Returns a reference to \p this object. /// /// \return a reference to \p this object AgentHandle self(void) noexcept override; /// Sends a given \c rosa::message_t instance to \p this object. /// /// \param M message to send /// /// \note Since a \c rosa::Agent instance is always valid, there is no /// precondition for this function. /// \see \c rosa::AbstractAgent::sendMessage and /// `rosa::Agent::operator bool() const` void sendMessage(message_t &&M) noexcept override; /// Dumps \p this object into a \c std::string for tracing purposes. /// /// \return \c std::string representing the state of \p this object std::string dump(void) const noexcept override; protected: /// Returns a reference to the \c rosa::MessagingSystem owning \p this object. /// /// \return reference of \c rosa::Unit::S MessagingSystem &system(void) const noexcept override; + + /// Gives the referenced \c rosa::Agent instance for a \c rosa::AgentHandle. + /// + /// \note Intended for derived classes to be able to inspect + /// \c rosa::AgentHandle instances. + /// + /// \param H \c rosa::AgentHandle to take the referenced \c rosa::Agent from + /// + /// \return reference to the \c rosa::Agent instance from \p H + static Agent &unwrapAgent(const AgentHandle &H) noexcept { return H.A; } + + /// Gives the owning \c rosa::MessagingSystem of a \c rosa::Agent instance + /// for a \c rosa::AgentHandle. + /// + /// \note Intended for for derived classes to be able to inspect + /// \c rosa::AgentHandle instances. + /// + /// \param H \c rosa::AgentHandle to take the owning + /// \c rosa::MessagingSystem from + /// + /// \return reference to the \c rosa::MessagingSystem owning the + /// \c rosa::Agent instance from \p H + static MessagingSystem &unwrapSystem(const AgentHandle &H) noexcept { + return H.S; + } }; template Agent::Agent(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, Fun &&F, Funs &&... Fs) : Unit(Kind, Id, Name, S), MessageHandler(std::move(F), std::move(Fs)...), Self(*this, /*valid*/ true) { LOG_TRACE("Agent is created."); } } // End namespace rosa #endif // ROSA_CORE_AGENT_HPP diff --git a/include/rosa/core/AgentHandle.hpp b/include/rosa/core/AgentHandle.hpp index 6e0f4b4..68df7b0 100644 --- a/include/rosa/core/AgentHandle.hpp +++ b/include/rosa/core/AgentHandle.hpp @@ -1,108 +1,302 @@ //===-- rosa/core/AgentHandle.hpp -------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/AgentHandle.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of a handle for \c rosa::Agent. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_AGENTHANDLE_HPP #define ROSA_CORE_AGENTHANDLE_HPP #include "rosa/core/AbstractAgent.hpp" namespace rosa { /// Wraps an actual \c rosa::Agent to decouple its public interface. /// \note Such decoupling might be necessary when operating with remote /// *systems*, sometime in the future. class AgentHandle : public AbstractAgent { /// \c rosa::Agent and \c rosa::MessagingSystem are our friends, they may /// inspect the private member fields of the class. ///@{ friend class Agent; friend class MessagingSystem; ///@} /// The wrapped \c rosa::Agent instance. Agent &A; /// The \c rosa::MessagingSystem owning \c A. MessagingSystem &S; /// Creates a new instance without validating the state of the wrapped /// \c rosa::Agent. /// /// \note Used by a \c rosa::Agent instance to create a reference to itself /// during construction, when its state is not valid yet. /// /// \param A \c rosa::Agent to wrap /// /// \note There a second argument, which is ignored, that is only present to /// separate this constructor from the public constructor taking only a /// \c rosa::Agent to wrap. - AgentHandle(Agent &A, bool); + AgentHandle(Agent &A, bool) noexcept; public: /// Creates a new instance validating the state of the wrapped \p rosa::Agent. /// /// \note The wrapped \c rosa::Agent must be in a valid state to instantiate /// \c rosa::AgentHandle with this constructor. /// /// \param A \c rosa::Agent to wrap /// /// \pre \p A is registered in its owning *system*:\code /// A.system().isUnitRegistered(A) /// \endcode AgentHandle(Agent &A); /// Destroys \p this object. /// /// The destructor has nothing to take care of. ~AgentHandle(void) = default; /// Tells if the wrapped \c rosa::Agent is in a valid state. /// /// \note A \c rosa::AgentHandler belongs to a \c rosa::MessagingSystem. /// Working with a \c rosa::AgentHandler whose originating /// \c rosa::MessagingSystem has already been destroyed results in *undefined* /// behavior. /// /// \return if the wrapped \c rosa::Agent is in a valid state operator bool(void) const noexcept override; /// Tells if another \c rosa::AgentHandle wraps the same \c rosa::Agent as /// \p this object. /// /// \param H \c rosa::AgentHandle whose wrapped \c rosa::Agent to check /// /// \return if \p H wraps \c A like \p this object bool operator==(const AgentHandle &H) const noexcept override; /// Returns a reference to the wrapped \c rosa::Agent. /// /// \return a reference to \c A AgentHandle self(void) noexcept override; /// Sends a given \c rosa::message_t instance to the wrapped \c rosa::Agent. /// /// \param M message to send /// /// \pre The wrapped \c rosa::Agent instance is in a valid state:\code /// bool(*this) /// \endcode void sendMessage(message_t &&M) noexcept override; }; + +/// Template specialization for optionally storing \c rosa::AgentHandle +/// instances. +/// +/// \ingroup Optional +/// +/// Due to \c rosa::AgentHandle not supporting copying and moving of instances, +/// the member functions in this class fall back to destroying the old stored +/// object and creating a new one whenever the stored value is to be changed. +template <> class Optional { +public: + using Type = AgentHandle; + + /// Creates an instance without value. + /// + /// \note Use it with its default parameter. + Optional(const none_t & = none) : Valid(false) {} + + /// Creates a valid instance with value. + /// + /// \param X value to store in the object + Optional(AgentHandle X) : Valid(false) { + cr(std::move(X)); + } + + /// Creates an instance as a copy of another one. + /// + /// \param Other the instance whose state to copy + Optional(const Optional &Other) : Valid(false) { + if (Other.Valid) { + cr(Other.Value); + } + } + + /// Creates an instance as a copy of another one. + /// + /// \param Other the instance whose state to obtain + Optional(Optional &&Other) noexcept : Valid(false) { + if (Other.Valid) { + cr(std::move(Other.Value)); + } + } + + /// Destroys \p this object. + ~Optional(void) { destroy(); } + + /// Updates \p this object by copying the state of another one. + /// + /// \param Other the instance whose state to copy + /// + /// \return reference of the updated instance + Optional &operator=(const Optional &Other) { + if (Valid) { + destroy(); + } + if (Other.Valid) { + cr(Other.Value); + } + return *this; + } + + /// Updates \p this object by copying the state of another one. + /// + /// \param Other the instance whose state to obtain + /// + /// \return reference of the updated instance + Optional &operator=(Optional &&Other) noexcept { + if (Valid) { + destroy(); + } + if (Other.Valid) { + cr(std::move(Other.Value)); + } + return *this; + } + + /// Checks whether \p this object contains a value. + /// + /// \return if \p this object contains a value + explicit operator bool(void) const { return Valid; } + + /// Checks whether \p this object does not contain a value. + /// + /// \return if \p this object does not contain a value + bool operator!(void)const { return !Valid; } + + /// Returns the value stored in \p this object. + /// + /// \return reference of the stored value + /// + /// \pre \p this object contains a value + AgentHandle &operator*(void) { + ASSERT(Valid); + return Value; + } + + /// Returns the value stored in \p this object. + /// + /// \return reference of the stored value + /// + /// \pre \p this object contains a value + const AgentHandle &operator*(void)const { + ASSERT(Valid); + return Value; + } + + /// Returns the value stored in \p this object. + /// + /// \return pointer to the stored value + /// + /// \pre \p this object contains a value + const AgentHandle *operator->(void)const { + ASSERT(Valid); + return &Value; + } + + /// Returns the value stored in \p this object. + /// + /// \return pointer of the stored value + /// + /// \pre \p this object contains a value + AgentHandle *operator->(void) { + ASSERT(Valid); + return &Value; + } + + /// Returns the value stored in \p this object. + /// + /// \return reference of the stored value + /// + /// \pre \p this object contains a value + AgentHandle &value(void) { + ASSERT(Valid); + return Value; + } + + /// Returns the value stored in \p this object. + /// + /// \return reference of the stored value + /// + /// \pre \p this object contains a value + const AgentHandle &value(void) const { + ASSERT(Valid); + return Value; + } + + /// Returns the stored value or a default. + /// + /// If \p this object contains a value, then the stored value is returned. A + /// given default value is returned otherwise. + /// + /// \param DefaultValue the value to return if \p this object does not contain + /// a value + /// + /// \return reference to either the stored value or \p DefaultValue if \p this + /// object does not contain a value + const AgentHandle &valueOr(const AgentHandle &DefaultValue) const { + return Valid ? Value : DefaultValue; + } + +private: + /// Deallocates the stored value if any. + void destroy(void) { + if (Valid) { + Value.~AgentHandle(); + Valid = false; + } + } + + /// Updates the state of \p this object by copying a value into it. + /// + /// \tparam V type of \p X + /// + /// \param X value to copy + /// + /// \pre \p this object does not contain a value + template void cr(V &&X) { + ASSERT(!Valid); + Valid = true; + new (&Value) AgentHandle(std::forward(X)); + } + + /// Denotes if \p this object contains a value. + bool Valid; + + /// Holds the stored value if any. + union { + AgentHandle Value; ///< The stored value. + }; +}; + + + + } // End namespace rosa #endif // ROSA_CORE_AGENTHANDLE_HPP diff --git a/include/rosa/core/Invoker.hpp b/include/rosa/core/Invoker.hpp index ad6399e..d13057e 100644 --- a/include/rosa/core/Invoker.hpp +++ b/include/rosa/core/Invoker.hpp @@ -1,273 +1,256 @@ //===-- rosa/core/Invoker.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Invoker.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for providing actual arguments for functions as /// \c rosa::Messageobjects. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_INVOKER_HPP #define ROSA_CORE_INVOKER_HPP #include "rosa/core/MessageMatcher.hpp" #include "rosa/support/log.h" +#include "rosa/support/sequence.hpp" #include #include namespace rosa { /// Wraps a function and provides a simple interface to invoke the stored /// function by passing actual arguments as a \c rosa::Message object. /// /// \note A \c rosa::Invoker instance is supposed to be owned by a /// \c rosa::MessageHandler instance, and not being used directly from user /// code. class Invoker { protected: /// Creates an instance. /// /// \note Protected constructor restricts instantiation to derived classes. Invoker(void) noexcept; public: /// Destroys \p this object. virtual ~Invoker(void); /// Possible results of an invocation. enum class Result { NoMatch, ///< The wrapped function could not be invoked Invoked ///< The wrapped function has been invoked }; /// Type alias for a smart-pointer for \c rosa::Invoker. using invoker_t = std::unique_ptr; /// Type alias for \c rosa::Invoker::Result. using result_t = Result; /// Tells if a \c rosa::Message object can be used to invoke the function /// wrapped in \p this object. /// /// \param Msg \c rosa::Message to check /// /// \return whether \p Msg can be used to invoke the wrapped function virtual bool match(const Message &Msg) const noexcept = 0; /// Tries to invoke the wrapped function with a \c rosa::Message object. /// /// The wrapped function is invoked if the actual \c rosa::Message object can /// be used to invoke it. /// /// \param Msg \c rosa::Message to try to invoke the wrapped function with /// /// \return whether the wrapped function could be invoked with \p Msg virtual result_t operator()(const Message &Msg) const noexcept = 0; /// Instantiates an implementation of \c rosa::Invoker with the given /// function. /// /// \note As there is no empty \c rosa::Message, no \c rosa::Invoker wraps a /// function without any argument. /// /// \tparam T type of the first mandatory argument /// \tparam Ts types of any further arguments /// /// \param F function to wrap /// /// \return new \c rosa::Invoker::invoker_t object created from the given /// function template static invoker_t wrap(std::function &&F) noexcept; /// Convenience template alias for casting callable stuff to function objects /// for wrapping. /// /// \tparam Ts types of arguments /// /// \todo Should make it possible to avoid using an explicit conversion for /// the arguments of wrap. template using F = std::function; + /// Convenience template for preparing non-static member functions into /// function objects for wrapping. /// /// \tparam C type whose non-static member the function is /// \tparam Ts types of arguments /// /// \see \c THISMEMBER template static inline F M(C *O, void (C::*Fun)(Ts...) noexcept) noexcept; }; /// Convenience preprocessor macro for the typical use of \c rosa::Invoker::M. /// It can be used inside a class to turn a non-static member function into a /// function object capturing this pointer, so using the actual object when /// handling a \c rosa::Message. /// /// \param FUN the non-static member function to wrap /// /// \note Inside the class \c MyClass, use\code /// THISMEMBER(fun) /// \endcode instead of\code /// Invoker::M(this, &MyClass::fun) /// \endcode #define THISMEMBER(FUN) \ Invoker::M(this, &std::decay::type::FUN) /// Nested namespace with implementation of \c rosa::Invoker and helper /// templates, consider it private. namespace { -/// \defgroup Seq -/// -///@{ - -/// Template with an empty struct to store a sequence of numbers in compile time -/// as template arguments. -template struct Seq {}; - -/// Sequence generator, the general case when counting down by extending the -/// sequence. -template struct GenSeq : GenSeq {}; - -/// Sequence generator, the terminal case when storing the generated sequence -/// into \c Seq. -template struct GenSeq<0, S...> { using Type = Seq; }; - -///@} - /// \defgroup InvokerImpl /// /// Implements the \c rosa::Invoker interface for functions with different /// signatures. /// ///@{ /// Declaration of \c rosa::InvokerImpl implementing \c rosa::Invoker. /// /// \tparam Fun function to wrap template class InvokerImpl; /// Implementation of \c rosa::InvokerImpl for \c std::function. /// /// \tparam T type of the first mandatory argument /// \tparam Ts types of further arguments /// /// \note As there is no empty \c rosa::Message, no \c rosa::Invoker wraps a /// function without any argument, i.e., no /// \c std::function. template class InvokerImpl> final : public Invoker { /// Type alias for the stored function. using function_t = std::function; /// Type alias for correctly typed argument-tuples as obtained from /// \c rosa::Message. using args_t = std::tuple; /// Alias for \c rosa::MessageMatcher for the arguments of the stored /// function. using Matcher = MsgMatcher; /// The wrapped function. const function_t F; /// Invokes \c InvokerImpl::F by unpacking arguments from a \c std::tuple with /// the help of the actual template arguments. /// /// \tparam S sequence of numbers indexing \c std::tuple for arguments /// /// \param Args arguments to invoke \c InvokerImpl::F with /// /// \pre the length of \p S and size of \p Args are matching:\code /// sizeof...(S) == std::tuple_size::value /// \endcode template inline void invokeFunction(Seq, const args_t &Args) const noexcept; public: /// Creates an instance. /// /// \param F function to wrap /// /// \pre \p F is valid:\code /// bool(F) /// \endcode InvokerImpl(function_t &&F) noexcept : F(F) { ASSERT(bool(F)); // Sanity check. } /// Destroys \p this object. ~InvokerImpl(void) = default; /// Tells if a \c rosa::Message object can be used to invoke the function /// wrapped in \p this object. /// /// \param Msg \c rosa::Message to check /// /// \return whether \p Msg can be used to invoke the wrapped function bool match(const Message &Msg) const noexcept override { return Matcher::doesStronglyMatch(Msg); }; /// Tries to invoke the wrapped function with a \c rosa::Message object. /// /// The wrapped function is invoked if the actual \c rosa::Message object can /// be used to invoke it. /// /// \param Msg \c rosa::Message to try to invoke the wrapped function with /// /// \return whether the wrapped function could be invoked with \p Msg result_t operator()(const Message &Msg) const noexcept override { if (match(Msg)) { LOG_TRACE("Invoking with matching arguments"); invokeFunction(typename GenSeq::Type(), Matcher::extractedValues(Msg)); return result_t::Invoked; } else { LOG_TRACE("Tried to invoke with non-matching arguments"); return result_t::NoMatch; } } }; template template void InvokerImpl>::invokeFunction( Seq, const args_t &Args) const noexcept { ASSERT(sizeof...(S) == std::tuple_size::value); // Sanity check. F(std::get(Args)...); } ///@} } // End namespace template Invoker::invoker_t Invoker::wrap(std::function &&F) noexcept { return std::unique_ptr( new InvokerImpl>(std::move(F))); } template Invoker::F Invoker::M(C *O, void (C::*Fun)(Ts...) noexcept) noexcept { return [ O, Fun ](Ts... Vs) noexcept->void { (O->*Fun)(Vs...); }; } - } // End namespace rosa #endif // ROSA_CORE_INVOKER_HPP diff --git a/include/rosa/core/Message.hpp b/include/rosa/core/Message.hpp index 8e7b66e..49e78aa 100644 --- a/include/rosa/core/Message.hpp +++ b/include/rosa/core/Message.hpp @@ -1,482 +1,257 @@ //===-- rosa/core/Message.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Message.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of \c rosa::Message base-class. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_MESSAGE_HPP #define ROSA_CORE_MESSAGE_HPP #include "rosa/support/log.h" -#include "rosa/support/type_token.hpp" +#include "rosa/support/tokenized_storages.hpp" #include "rosa/core/forward_declarations.h" -#include -#include - namespace rosa { /// *Message* interface. /// /// The interface provides means to check the type of the stored values, but /// actual data is to be managed by derived implementations. /// /// A \c rosa::Message instance is an immutable data object that obtains its /// data upon creation and provides only constant references for the stored /// values. /// /// \note Any reference obtained from a \c rosa::Message instance remains valid /// only as long as the owning \c rosa::Message object is not destroyed. +/// +/// \todo Some member functions of \c rosa::Message duplicate member functions +/// of \c rosa::TokenizedStorage, which cannot be easily factored out into a +/// common base class due to eventual diamond inheritance issues in derived +/// classes. Could this duplication be avoided? class Message { protected: /// Creates a new instance. /// /// \note No implementation for empty list. /// /// \tparam Type type of the mandatory first argument /// \tparam Types types of any further arguments /// /// \note the actual arguments are ignored by the constructor it is only /// their type that matters. The actual values are supposed to be handled by /// any implementation derived from \c rosa::Message. /// /// \pre \p Type and \p Types are all built-in types and the number of stored /// values does not exceed \c rosa::token::MaxTokenizableListSize. template Message(const Type &, const Types &...) noexcept; /// No copying and moving of \c rosa::Message instances. ///@{ Message(const Message &) = delete; Message(Message &&) = delete; Message &operator=(const Message &) = delete; Message &operator=(Message &&) = delete; ///@} public: /// Creates a \c rosa::message_t object from constant lvalue references. /// /// \tparam Type type of the mandatory first argument /// \tparam Types types of any further arguments /// /// \param T the first value to include in the \c rosa::Message /// \param Ts optional further values to include in the \c rosa::Message /// /// \return new \c rosa::message_t object created from the given arguments template static message_t create(const Type &T, const Types &... Ts) noexcept; /// Creates a \c rosa::message_t object from rvalue references. /// /// \tparam Type type of the mandatory first argument /// \tparam Types types of any further arguments /// /// \param T the first value to include in the \c rosa::Message /// \param Ts optional further values to include in the \c rosa::Message /// /// \return new \c rosa::message_t object created from the given arguments template static message_t create(Type &&T, Types &&... Ts) noexcept; /// Represents the types of the values stored in \p this object. /// /// A valid, non-empty \c rosa::Token representing the types of the values /// stored in \p this object. const Token T; /// The number of values stored in \p this object. /// /// That is the number of types encoded in \c rosa::Message::T. const size_t Size; /// Destroys \p this object. virtual ~Message(void); /// Tells if the value stored at a given index is of a given type. /// /// \note Any \c rosa::AtomConstant is encoded in \c rosa::Token as /// the \c rosa::AtomValue wrapped into it. /// /// \tparam Type type to match against /// /// \param Pos index the type of the value at is to be matched against \p Type /// /// \return if the value at index \p Pos of type \p Type /// /// \pre \p Pos is a valid index:\code /// Pos < Size /// \endcode template bool isTypeAt(const size_t Pos) const noexcept; /// Gives a constant reference of a value of a given type stored at a given /// index. /// /// \tparam Type type to give a reference of /// /// \param Pos index to set the reference for /// /// \return constant reference of \p Type for the value stored at index \p Pos /// /// \pre \p Pos is a valid index and the value at index \p Pos is of type /// \p Type:\code - /// Pos < Size && isTypeAt(Pos) + /// Pos < Size && isTypeAt(Pos) /// \endcode template const Type &valueAt(const size_t Pos) const noexcept; protected: /// Provides an untyped pointer for the value at a given index. /// /// \param Pos index to take a pointer for /// /// \return untyped pointer for the value stored at index \p Pos /// /// \pre \p Pos is a valid index:\code /// Pos < Size /// \endcode virtual const void *pointerTo(const size_t Pos) const noexcept = 0; }; /// Nested namespace with implementation for \c rosa::Message, consider it /// private. namespace { /// Template class for an implementation of \c rosa::Message. /// /// \tparam Types types whose values are to be stored template class LocalMessage; -/// Initializes a pre-allocated memory area with values from constant lvalue -/// references. -/// -/// \tparam Types types whose values are to be stored -/// -/// \param Arena pre-allocated memory area to store values to -/// \param Ts the values to store in \p Arena -/// -/// \note \p Arena needs to be a valid pointer to a memory area big enough for -/// values of \p Types. -template -inline void createMessageElements(void *const Arena, - const Types &... Ts) noexcept; - -/// \defgroup createMessageElement from const lvalue references -/// -/// Stores values from constant lvalue references into a pre-allocated memory -/// area. -/// -/// \note To be used by the implementation of \c createMessageElements. -/// -/// \todo Document these functions. -///@{ - -/// \note This terminal case is used for both constant lvalue references and -/// value references. -template -inline void createMessageElement(void *const, - const std::vector &Offsets) { - ASSERT(Pos == Offsets.size()); -} - -template -inline void createMessageElement(void *const Arena, - const std::vector &Offsets, - const Type &T, const Types &... Ts) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - new (static_cast(static_cast(static_cast(Arena) + - Offsets[Pos]))) Type(T); - createMessageElement(Arena, Offsets, Ts...); -} - -template -inline void -createMessageElement(void *const Arena, const std::vector &Offsets, - const AtomConstant &, const Types &... Ts) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - *static_cast( - static_cast(static_cast(Arena) + Offsets[Pos])) = V; - createMessageElement(Arena, Offsets, Ts...); -} - -///@} - -/// Implementation of the template. -/// -/// \tparam Type the type of the mandatory first value to store -/// \tparam Types types of any further values to store -/// -/// \param Arena pre-allocated memory area to store values to -/// \param T the first value to store in \p ArenaË› -/// \param Ts optional further values to store in \p Arena -/// -/// \pre \p Arena is not \p nullptr. -template -inline void createMessageElements(void *const Arena, const Type &T, - const Types &... Ts) noexcept { - ASSERT(Arena != nullptr); - createMessageElement<0>(Arena, LocalMessage::Offsets, T, - Ts...); -} - -/// Initializes a pre-allocated memory area with values from rvalue references. -/// -/// \tparam Types types whose values are to be stored -/// -/// \param Arena pre-allocated memory area to store values to -/// \param Ts the values to store in \p Arena -/// -/// \note \p Arena needs to be a valid pointer to a memory area big enough for -/// values of \p Types. -template -inline void createMessageElements(void *const Arena, Types &&... Ts) noexcept; - -/// \defgroup createMessageElement from rvalue references -/// -/// Stores values from rvalue references into a pre-allocated memory area. -/// -/// \note To be used by the implementation of \c createMessageElements. -/// -/// \todo Document these functions. -///@{ - -template -inline void createMessageElement(void *const Arena, - const std::vector &Offsets, Type &&T, - Types &&... Ts) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - new (static_cast(static_cast( - static_cast(Arena) + Offsets[Pos]))) Type(std::move(T)); - createMessageElement(Arena, Offsets, std::move(Ts)...); -} - -template -inline void createMessageElement(void *const Arena, - const std::vector &Offsets, - AtomConstant &&, Types &&... Ts) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - *static_cast( - static_cast(static_cast(Arena) + Offsets[Pos])) = V; - createMessageElement(Arena, Offsets, std::move(Ts)...); -} - -///@} - -/// Implementation of the template. -/// -/// \tparam Type the type of the mandatory first value to store -/// \tparam Types types of any further values to store -/// -/// \param Arena pre-allocated memory area to store values to -/// \param T the first value to store in \p Arena -/// \param Ts optional further values to store in \p Arena -/// -/// \pre \p Arena is not \c nullptr. -template -inline void createMessageElements(void *const Arena, Type &&T, - Types &&... Ts) noexcept { - ASSERT(Arena != nullptr); - createMessageElement<0>(Arena, LocalMessage::Offsets, - std::move(T), std::move(Ts)...); -} - -/// Destroys values allocated by \c createMessageElements. -/// -/// \tparam Type type of the mandatory first value stored in \p Arena -/// \tparam Types futher types whose values are stored in \p Arena -/// -/// \param Arena the memory area to destroy values from -/// -/// \note \p Arena needs to be a valid pointer to a memory area where values of -/// \p Types are stored. -template -inline void destroyMessageElements(void *const Arena) noexcept; - -/// \defgroup destroyMessageElement -/// -/// Destroys values from a memory area. -/// -/// \note To be used by the implementation of \c destroyMessageElements. -/// -/// \todo Document these functions. -///@{ - -template -inline void destroyMessageElement(void *const, - const std::vector &Offsets) noexcept { - ASSERT(Pos == Offsets.size()); -} - -template -inline void destroyMessageElement(void *const Arena, - const std::vector &Offsets) noexcept { - ASSERT(Arena != nullptr && Pos < Offsets.size()); - static_cast( - static_cast(static_cast(Arena) + Offsets[Pos])) - ->~Type(); - destroyMessageElement(Arena, Offsets); -} - -///@} - -/// Implementation of the template. -/// -/// \tparam Type the type of the mandatory first value to destroy -/// \tparam Types types of any further values to destroy -/// -/// \param Arena the memory area to destroy values from -/// -/// \pre \p Arena is not \c nullptr. -template -inline void destroyMessageElements(void *const Arena) noexcept { - ASSERT(Arena != nullptr); - destroyMessageElement<0, Type, Types...>( - Arena, LocalMessage::Offsets); -} - /// Implementation of the template \c rosa::LocalMessage providing facilities /// for storing values as a \c rosa::Message object. /// /// \tparam Type type of the first mandatory value of the \c rosa::Message /// \tparam Types of any further values template -class LocalMessage : public Message { -public: - /// \c rosa::Token for the stored values. - /// - /// \note Only for compile-time checks! This static member is not defined - /// because it must be the same as \c rosa::Message::T. - static constexpr Token ST = - TypeToken::type, - typename std::decay::type...>::Value; - - /// Byte offsets to access stored values in \c LocalMessage::Arena. - static const std::vector Offsets; - -private: - /// A BLOB storing all the values one after the other. - void *const Arena; - - /// Generates byte offsets for accessing values stored in - /// \c LocalMessage::Arena. - /// - /// \return \c std::vector containing byte offsets for accessing values stored - /// in \c LocalMessage::Arena - static std::vector offsets(void) noexcept { - Token T = ST; // Need a mutable copy. - const size_t N = lengthOfToken(T); // Number of types encoded in \c T. - size_t I = 0; // Start indexing from position \c 0. - std::vector O(N); // Allocate vector of proper size. - O[0] = 0; // First offset is always \c 0. - while (I < N - 1) { - ASSERT(I + 1 < O.size() && lengthOfToken(T) == N - I); - // Calculate next offset based on the previous one. - // \note The offset of the last value is stored at `O[N - 1]`, which is - // set when `I == N - 2`. Hence the limit of the loop. - O[I + 1] = O[I] + sizeOfHeadOfToken(T); - dropHeadOfToken(T), ++I; - } - ASSERT(I + 1 == O.size() && lengthOfToken(T) == 1); - return O; - } - +class LocalMessage final + : public Message, + private TokenizedStorage { public: /// Creates an instance from constant lvalue references. /// /// \param T the mandatory first value to store in the \c rosa::Message object /// \param Ts optional further values to store in the \c rosa::Message object LocalMessage(const Type &T, const Types &... Ts) noexcept : Message(T, Ts...), - Arena(::operator new(sizeOfValuesOfToken(ST))) { - ASSERT(this->T == ST && Size == Offsets.size() && - Arena != nullptr); // Sanity check. - createMessageElements(Arena, T, Ts...); + TokenizedStorage(T, Ts...) { + ASSERT(this->T == this->ST && Size == this->size()); // Sanity check. } /// Creates an instance from rvalue references. /// /// \param T the mandatory first value to store in the \c rosa::Message object /// \param Ts optional further values to store in the \c rosa::Message object LocalMessage(Type &&T, Types &&... Ts) noexcept : Message(T, Ts...), - Arena(::operator new(sizeOfValuesOfToken(ST))) { - ASSERT(this->T == ST && Size == Offsets.size() && - Arena != nullptr); // Sanity check. - createMessageElements(Arena, std::move(T), std::move(Ts)...); - } - - // Destroys \p this object. - ~LocalMessage(void) { - destroyMessageElements(Arena); - ::operator delete(Arena); + TokenizedStorage(std::move(T), std::move(Ts)...) { + ASSERT(this->T == this->ST && Size == this->size()); // Sanity check. } /// Provides an untyped pointer for the constant value stored at a position. /// /// \param Pos the index of the value to return an untyped pointer for /// /// \return untyped pointer for the constant value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < Size + /// \endcode const void *pointerTo(const size_t Pos) const noexcept override { - ASSERT(Pos < Offsets.size()); - return static_cast(Arena) + Offsets[Pos]; + ASSERT(Pos < Size); + return TokenizedStorage::pointerTo(Pos); } -}; -// Implementation of the static member field \c LocalMessage::Offsets. -template -const std::vector LocalMessage::Offsets = - LocalMessage::offsets(); + /// Aborts the program! + /// + /// Since \c rosa::Message instances are supposed to be immutable, the + /// non-const inherited function is overridden so that it aborts execution. + void *pointerTo(const size_t) noexcept override { + ROSA_CRITICAL("Unallowed operation of rosa::LocalMessage"); + } +}; } // End namespace template Message::Message(const Type &, const Types &...) noexcept : T(TypeToken::type, typename std::decay::type...>::Value), Size(lengthOfToken(T)) { ASSERT(validToken(T) && lengthOfToken(T) == (1 + sizeof...(Types))); // Sanity check. LOG_TRACE("Creating Message with Token(" + to_string(T) + ")"); } /// \note The implementation instantiates a private local template class /// \c LocalMessage. template message_t Message::create(const Type &T, const Types &... Ts) noexcept { return message_t(new LocalMessage(T, Ts...)); } /// \note The implementation instantiates a private local template class /// \c LocalMessage. template message_t Message::create(Type &&T, Types &&... Ts) noexcept { return message_t( new LocalMessage(std::move(T), std::move(Ts)...)); } template bool Message::isTypeAt(const size_t Pos) const noexcept { ASSERT(Pos < Size); Token TT = T; dropNOfToken(TT, Pos); return isHeadOfTokenTheSameType(TT); } template const Type &Message::valueAt(const size_t Pos) const noexcept { ASSERT(Pos < Size && isTypeAt(Pos)); return *static_cast(pointerTo(Pos)); } } // End namespace rosa #endif // ROSA_CORE_MESSAGE_HPP diff --git a/include/rosa/core/MessagingSystem.hpp b/include/rosa/core/MessagingSystem.hpp index cb81c44..5b6fd14 100644 --- a/include/rosa/core/MessagingSystem.hpp +++ b/include/rosa/core/MessagingSystem.hpp @@ -1,186 +1,198 @@ //===-- rosa/core/MessagingSystem.hpp ---------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/MessagingSystem.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of an interface extending \c rosa::System with messaging. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_MESSAGINGSYSTEM_HPP #define ROSA_CORE_MESSAGINGSYSTEM_HPP #include "rosa/core/AgentHandle.hpp" #include "rosa/core/System.hpp" #include "rosa/support/atom.hpp" namespace rosa { /// Extends the \c rosa::System interface with features to create \c rosa::Agent /// instancess and register \c rosa::Message objects for them. class MessagingSystem : public System { friend class AgentHandle; ///< \c rosa::AgentHandle is our friend. public: /// Returns an object implementing the \c rosa::MessagingSystem interface. /// /// \param Name name of the new instance /// /// \return \c std::unique_ptr for the new instance of /// \c rosa::MessagingSystem static std::unique_ptr createSystem(const std::string &Name) noexcept; private: /// Kind for categorizing \c rosa::Unit instances as *agents*. static constexpr AtomValue AgentKind = atom("agent"); protected: /// Creates a new instance. /// /// \note Protected constructor restricts instantiation for subclasses. MessagingSystem(void) noexcept = default; protected: /// Creates a \c rosa::Agent instance owned by \p this object and returns a /// \c rosa::AgentHandle for it. /// /// \tparam T type of the actual \c rosa::Agent to instantiate /// \tparam Funs types of the functions to instantiate \c rosa::Agent with /// /// \note \c rosa::Agent requires at least one function for its constructor, /// but derived classes may do not need that. That's the reason of allowing /// zero \p Funs for this template function. /// /// \param Name name of the new \c rosa::Unit instance /// \param Fs functions to instantiate \c rosa::Unit with /// /// \pre Statically, \p T is a subclass of \c rosa::Agent:\code /// std::is_base_of::value /// \endcode template AgentHandle createAgent(const std::string &Name, Funs &&... Fs); - /// Gives the references \c rosa::Agent instance for a \c rosa::AgentHandle. + /// Unregisters and destroys a \c rosa::Agent referred by a + /// \c rosa::AgentHandle. + /// + /// The function uses \c rosa::System::destroyUnit. + /// + /// \param H refers to the \c rosa::Agent to destroy + /// + /// \pre The referred \c rosa::Agent is registered. + /// + /// \post The referred \c rosa::Agent is not registered and also destroyed. + void destroyAgent(const AgentHandle &H) noexcept; + + /// Gives the referenced \c rosa::Agent instance for a \c rosa::AgentHandle. /// /// \note Intended for derived classes to be able to inspect /// \c rosa::AgentHandle instances. /// /// \param H \c rosa::AgentHandle to take the referenced \c rosa::Agent from /// /// \return reference to the \c rosa::Agent instance from \p H static Agent &unwrapAgent(const AgentHandle &H) noexcept { return H.A; } /// Gives the owning \c rosa::MessagingSystem of a \c rosa::Agent instance /// for a \c rosa::AgentHandle. /// /// \note Intended for for derived classes to be able to inspect /// \c rosa::AgentHandle instances. /// /// \param H \c rosa::AgentHandle to take the owning /// \c rosa::MessagingSystem from /// /// \return reference to the \c rosa::MessagingSystem owning the /// \c rosa::Agent instance from \p H static MessagingSystem &unwrapSystem(const AgentHandle &H) noexcept { return H.S; } public: /// Sends a \c rosa::message_t instance to the \c rosa::Agent instance /// referred by a \c rosa::AgentHandle. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \param H refers to the \c rosa::Agent instance to send to /// \param M message to send /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode virtual void send(const AgentHandle &H, message_t &&M) noexcept = 0; /// Sends a message -- created from given constant lvalue references -- /// to the \c rosa::Agent instance referred by a \c rosa::AgentHandle. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \note The message must consists of at least one value. /// /// \tparam Type type of the first mandatory value /// \tparam Types types of any further values /// /// \param H refers to the \c rosa::Agent instance to send to /// \param T the first value to include in the message /// \param Ts optional further values to include in the message /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode template void send(const AgentHandle &H, const Type &T, const Types &... Ts) noexcept; /// Sends a message -- created from given rvalue references -- /// to the \c rosa::Agent instance referred by a \c rosa::AgentHandle. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \note The message must consists of at least one value. /// /// \tparam Type type of the first mandatory value /// \tparam Types types of any further values /// /// \param H refers to the \c rosa::Agent instance to send to /// \param T the first value to include in the message /// \param Ts optional further values to include in the message /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode template void send(const AgentHandle &H, Type &&T, Types &&... Ts) noexcept; }; template AgentHandle MessagingSystem::createAgent(const std::string &Name, Funs &&... Fs) { STATIC_ASSERT((std::is_base_of::value), "not an Agent"); Agent &A = createUnit([&](const id_t Id, MessagingSystem &S) noexcept { return new T(AgentKind, Id, Name, S, std::move(Fs)...); }); return {A}; } template void MessagingSystem::send(const AgentHandle &H, const Type &T, const Types &... Ts) noexcept { send(H, Message::create(T, Ts...)); } template void MessagingSystem::send(const AgentHandle &H, Type &&T, Types &&... Ts) noexcept { send(H, Message::create(std::move(T), std::move(Ts)...)); } } // End namespace rosa #endif // ROSA_CORE_MESSAGINGSYSTEM_HPP diff --git a/include/rosa/core/System.hpp b/include/rosa/core/System.hpp index 3470bcb..f104180 100644 --- a/include/rosa/core/System.hpp +++ b/include/rosa/core/System.hpp @@ -1,214 +1,212 @@ //===-- rosa/core/System.hpp ------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/System.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of *System* interface. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_SYSTEM_HPP #define ROSA_CORE_SYSTEM_HPP #include "rosa/config/config.h" #include "rosa/core/forward_declarations.h" #include "rosa/support/debug.hpp" #include "rosa/support/log.h" #include #include #include namespace rosa { /// Base interface for actual agent-systems. /// /// The class provides facilities to keep track of \c rosa::Unit instances owned /// by a \c rosa::System. /// /// \note Any subclass is supposed to provide thread-safe implementation. /// /// \note The class declares only an interface to avoid trouble with multiple /// inheritance in various subclasses as in derived interfaces and derived /// implementations. /// /// \note Actual implementations are supposed to derive from \c rosa::SystemBase /// implenenting a base feature-set. class System { public: /// Signature of creator functions for \c rosa::Unit instances. /// /// \tparam T type derived from \c rosa::Unit /// \tparam S type derived from \c rosa::System template using UnitCreator = std::function; /// Returns an object implementing the \c rosa::System interface. /// /// \param Name name of the new instance /// /// \return \c std::unique_ptr for a new instance of \c rosa::System static std::unique_ptr createSystem(const std::string &Name) noexcept; protected: /// Creates an instance. /// /// \note Protected constructor restricts instantiation for subclasses. System(void) noexcept = default; /// No copying and moving of \c rosa::System. ///@{ System(const System &) = delete; System(System &&) = delete; System &operator=(const System &) = delete; System &operator=(System &&) = delete; ///@} public: /// Destroys \p this object. /// /// \note Any implementation makes sure that a \c rosa::System can be /// destroyed only if it is marked *cleaned* /// \see \c rosa::System::isSystemCleaned virtual ~System(void) = default; protected: /// Tells the next unique identifier to be used for a newly created /// \c rosa::Unit. /// /// \return \c rosa::id_t which is unique within the context of \p this /// object. /// /// \note Never returs the same value twice. virtual id_t nextId(void) noexcept = 0; /// Tells if \p this object has been marked cleaned and is ready for /// destruction. /// /// \return if \p this object is marked clean. virtual bool isSystemCleaned(void) const noexcept = 0; /// Marks \p this object cleaned. /// /// \note Can be called only once when the System does not have any live /// \c rosa::Unit instances. /// /// \pre \p this object has not yet been marked as cleaned and it has no /// \c rosa::Unit instances registered:\code /// !isSystemCleaned() && empty() /// \endcode /// /// \post \p this object is marked cleaned:\code /// isSystemCleaned() /// \encode virtual void markCleaned(void) noexcept = 0; /// Registers a \c rosa::Unit instance to \p this object. /// /// \param U \c rosa::Unit to register /// /// \pre \p this object has not yet been marked as cleaned and \p U is not /// registered yet:\code /// !isSystemCleaned() && !isUnitRegistered(U) /// \endcode /// /// \post \p U is registered:\code /// isUnitRegistered(U) /// \endcode virtual void registerUnit(Unit &U) noexcept = 0; /// Unregisters and destroys a registered \c rosa::Unit instance. /// /// \param U \c rosa::Unit to destroy /// /// \pre \p U is registered:\code /// isUnitRegistered(U) /// \endcode /// - /// \post \p U is not registered:\code - /// !isUnitRegistered(U) - /// \endcode Moreover, \p U is destroyed. + /// \post \p U is not registered and also destroyed. virtual void destroyUnit(Unit &U) noexcept = 0; /// Tells if a \c rosa::Unit is registered in \p this object. /// /// \param U \c rosa::Unit to check /// /// \return whether \p U is registered in \p this object virtual bool isUnitRegistered(const Unit &U) const noexcept = 0; /// Creates a \c rosa::Unit instance with the given /// \c rosa::System::UnitCreator and registers the new instance. /// /// \tparam T type of the actual \c rosa::Unit to instantiate /// \tparam S type of the actual \c rosa::System instantiating /// /// \param C function creating an instance of type \p T /// /// \note \p S must be the actual subclass that wants to instantiate /// \c rosa::Unit. That cannot be statically enforced, it is the /// reponsibility of the caller to provide the proper \c rosa::System /// subclass. /// /// \pre Statically, \p T is a subclass of \c rosa::Unit and \p S is a /// subclass of \c rosa::System:\code /// std::is_base_of::value && std::is_base_of::value /// \endcode Dynamically, \p this object has not yet been marked cleaned:\code /// !isSystemCleaned() /// \endcode template T &createUnit(UnitCreator C) noexcept; public: /// Tells the name of \p this object /// /// \note The returned reference remains valid as long as \p this object is /// not destroyed. /// /// \return name of \p this object virtual const std::string &name(void) const noexcept = 0; /// Tells the number of \c rosa::Unit instances constructed in the context of /// \p this object so far, including those being already destroyed. /// /// \return number of \c rosa::Unit instances created so far virtual size_t numberOfConstructedUnits(void) const noexcept = 0; /// Tells the number of live \c rosa::Unit instances in the context \p this /// object, those being constructed and not destroyed yet. /// /// \return number of \c rosa::Unit instances alive virtual size_t numberOfLiveUnits(void) const noexcept = 0; /// Tells if \p this object has no live \c rosa::Unit instances. /// /// \return whether \p this object has any live \c rosa::Unit instances virtual bool empty(void) const noexcept = 0; }; template T &System::createUnit(UnitCreator C) noexcept { STATIC_ASSERT((std::is_base_of::value), "not a Unit"); STATIC_ASSERT((std::is_base_of::value), "not a System"); if (isSystemCleaned()) { ROSA_CRITICAL("Trying to create a Unit in a cleaned System (" + name() + ")"); } const id_t Id = nextId(); T *U = C(Id, static_cast(*this)); registerUnit(*U); LOG_TRACE("Unit created and registered (" + U->FullName + ")"); return *U; } } // End namespace rosa #endif // ROSA_CORE_SYSTEM_HPP diff --git a/include/rosa/core/forward_declarations.h b/include/rosa/core/forward_declarations.h index 1fcc8e1..f11f2e0 100644 --- a/include/rosa/core/forward_declarations.h +++ b/include/rosa/core/forward_declarations.h @@ -1,40 +1,40 @@ //===-- rosa/core/forward_declarations.h ------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/forward_declarations.h /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Necessary forward declarations of types in the *Core* library. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_FORWARD_DECLARATIONS_H #define ROSA_CORE_FORWARD_DECLARATIONS_H -#include +#include // NOLINT namespace rosa { // Forward declarations of classes. class Agent; class Message; class MessagingSystem; class System; class Unit; /// Type alias used for \c rosa::Unit identifiers. using id_t = uint64_t; /// Type of a \c std::unique_ptr for an immutable *Message*, \c rosa::Message /// instance. -using message_t = std::unique_ptr; +using message_t = std::unique_ptr; } // End namespace rosa #endif // ROSA_CORE_FORWARD_DECLARATIONS_H diff --git a/include/rosa/deluxe/DeluxeAgent.hpp b/include/rosa/deluxe/DeluxeAgent.hpp new file mode 100755 index 0000000..d71db01 --- /dev/null +++ b/include/rosa/deluxe/DeluxeAgent.hpp @@ -0,0 +1,667 @@ +//===-- rosa/deluxe/DeluxeAgent.hpp -----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/deluxe/DeluxeAgent.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Specialization of \c rosa::Agent for *agent* role of the *deluxe +/// interface*. +/// +/// \see \c rosa::deluxe::DeluxeContext +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_DELUXE_DELUXEAGENT_HPP +#define ROSA_DELUXE_DELUXEAGENT_HPP + +#include "rosa/core/Agent.hpp" + +#include "rosa/deluxe/DeluxeAtoms.hpp" + +#include + +/// Local helper macros to deal with built-in types. +/// +///@{ + +/// Creates function name for member functions in \c rosa::deluxe::DeluxeAgent. +/// +/// \param N name suffix to use +#define DAHANDLERNAME(N) handleSlave_##N + +/// Defines member functions for handling messages from *slaves* in +/// \c rosa::deluxe::DeluxeAgent. +/// +/// \see \c DeluxeAgentInputHandlers +/// +/// \note No pre- and post-conditions are validated directly by these functions, +/// they rather rely on \c rosa::deluxe::DeluxeAgent::saveInput to do that. +/// +/// \param T the type of input to handle +/// \param N name suffix for the function identifier +#define DAHANDLERDEFN(T, N) \ + void DAHANDLERNAME(N)(atoms::Slave, id_t Id, T Value) noexcept { \ + saveInput(Id, Value); \ + } + +/// Convenience macro for \c DAHANDLERDEFN with identical arguments. +/// +/// \see \c DAHANDLERDEFN +/// +/// This macro can be used instead of \c DAHANDLERDEFN if the actual value of +/// \p T can be used as a part of a valid identifier. +/// +/// \param T the type of input to handle +#define DAHANDLERDEF(T) DAHANDLERDEFN(T, T) + +/// Results in a \c THISMEMBER reference to a member function defined by +/// \c DAHANDLERDEFN. +/// +/// Used in the constructor of \c rosa::deluxe::DeluxeAgent to initialize super +/// class \c rosa::Agent with member function defined by \c DAHANDLERDEFN. +/// +/// \see \c DAHANDLERDEFN, \c THISMEMBER +/// +/// \param N name suffix for the function identifier +#define DAHANDLERREF(N) THISMEMBER(DAHANDLERNAME(N)) + +///@} + +namespace rosa { +namespace deluxe { + +/// Specialization of \c rosa::Agent for *agent* role of the *deluxe interface*. +/// +/// \see \c rosa::deluxe::DeluxeContext +/// +/// \invariant All input-related container objects have a size matching +/// \c rosa::deluxe::DeluxeAgent::NumberOfInputs, thus having a corresponding +/// entry for each input. Types of input values are consistent throughout all +/// the input-related containers. No *slave* is registered at more than one +/// input position. *Slave* registrations and corresponding reverse lookup +/// information are consistent. +/// +/// \see Definition of \c rosa::deluxe::DeluxeAgent::inv on the class invariant +/// +/// \note All member functions validate the class invariant as part of their +/// precondition. Moreover, non-const functions validate the invariant before +/// return as their postcondition. +class DeluxeAgent : public Agent { + /// Checks whether \p this object holds the class invariant. + /// + /// \see Invariant of the class \c rosa::deluxe::DeluxeAgent + /// + /// \return if \p this object holds the class invariant + bool inv(void) const noexcept; + +public: + /// Template alias for function objects used to process input and generate + /// output for \c rosa::deluxe::DeluxeAgent. + /// + /// \tparam T type of output + /// \tparam A type of mandatory first input value + /// \tparam As types of further optional input values + template + using D = + std::function, std::pair...) noexcept>; + + /// The type of values produced by \p this object. + /// + /// That is the type of values \p this object sends to its *master*. + /// + /// \see \c rosa::deluxe::DeluxeAgent::master + const TypeNumber OutputType; + + /// Number of inputs processed by \p this object. + const size_t NumberOfInputs; + +private: + + /// Types of input values produced by *slaves* of \p this object. + /// + /// \note The \c rosa::TypeNumber values stored here match the corresponding + /// values in \c rosa::deluxe::DeluxeAgent::InputValues. + /// + /// \note The position of a type in the \c std::vector indicates which + /// argument of \p this object's processing function it belongs to. See also + /// \c rosa::deluxe::DeluxeAgent::D. + const std::vector InputTypes; + + /// Indicates whether any particular input value has been changed since the + /// last trigger received from the system. + /// + /// All the flags are reset to \c false upon handling a trigger and then set + /// to \c true by \c rosa::deluxe::DeluxeAgent::saveInput when storing a new + /// input value in \c rosa::deluxe::DeluxeAgent::InputValues. + /// + /// \note The position of a flag in the \c std::vector indicates which + /// argument of \p this object's processing function it belongs to. See also + /// \c rosa::deluxe::DeluxeAgent::D. + std::vector InputChanged; + + /// Stores the actual input values. + /// + /// \note The types of stored values match the corresponding + /// \c rosa::TypeNumber values in \c rosa::deluxe::DeluxeAgent::InputTypes. + /// + /// \note The position of a value in the \c rosa::AbstractTokenizedStorage + /// indicates which argument of \p this object's processing function it is. + /// See also \c rosa::deluxe::DeluxeAgent::D. + const std::unique_ptr InputValues; + + /// Alias for function objects used as trigger handler for + /// \c rosa::deluxe::DeluxeAgent. + /// + /// \see \c rosa::deluxe::DeluxeAgent::FP + using H = std::function; + + /// Handles trigger from the system. + /// + /// The actual function processing *slave* inputs and generating output to + /// *master* is captured in a lambda expression that is in turn wrapped in a + /// \c std::function object. The lambda expression calls the processing + /// function with the actual input data and sends its result to *master* by + /// calling \c rosa::deluxe::DeluxeAgent::sendToMaster. Also, all the flags + /// stored in \c rose::deluxe::DeluxeAgent::InputChanged are reset when the + /// current input values are processed. The function + /// \c rosa::deluxe::DeluxeAgent::handleTrigger needs only to call the + /// function object. + /// + /// \see \c rosa::deluxe::DeluxeAgent::triggerHandlerFromProcessingFunction + const H FP; + + /// The *master* to send values to. + /// + /// \note *Masters* are set dynamically, hence it is possible that a + /// \c rosa::deluxe::DeluxeAgent instance does not have any *master* at a + /// given moment. + Optional Master; + + /// The *slaves* sending input to \p this object. + /// + /// \note The position of a *slave* in the \c std::vector indicates which + /// argument of \p this object's processing function it belongs to. See also + /// \c rosa::deluxe::DeluxeAgent::D. + /// + /// \note *Slaves* are set dynamically, hence it is possible that a + /// \c rosa::deluxe::DeluxeAgent instance does have input positions without + /// any *slave* associated to them. + /// + /// \note Reverse lookup information is maintained in + /// \c rosa::deluxe::DeluxeAgent::SlaveIds, which is to be kept in sync with + /// the *slaves* stored here. + std::vector> Slaves; + + /// Associates \c rosa::id_t values to corresponding indices of registered + /// *slaves*. + /// + /// \see \c rosa::deluxe::DeluxeAgent::Slaves + std::map SlaveIds; + + /// Tells whether types \p As... match the input types of \p this object. + /// + /// \tparam As types to match against values in + /// \c rosa::deluxe::DeluxeAgent::InputTypes + /// + /// \return if types \p As... match \c rosa::TypeNumber values stored in + /// \c rosa::deluxe::DeluxeAgent::InputTypes + template bool inputTypesMatch(void) const noexcept; + + /// Gives an \c std::tuple containing the current input values and their + /// change flags so that they can be used for the processing function. + /// + /// \tparam As types of the input values + /// \tparam S0 indices for accessing input values and their change flags + /// + /// \note The only argument provides indices statically as template arguments + /// \p S0..., so its actual value is ignored. + /// + /// \return current input values and their change flags prepared for invoking + /// the processing function with them + /// + /// \pre The type arguments \p As... match the input types of \p this object + /// and the provided indices \p S0... constitute a proper sequence for + /// accessing input values and their change flags: \code + /// inputTypesMatch() && sizeof...(As) == sizeof...(S0) + /// \endcode + template + std::tuple...> prepareCurrentInputs(Seq) const + noexcept; + + /// Invokes a processing function matching the output and input types of \p + /// this object with actual arguments provided in a \c std::tuple. + /// + /// \note \p Args providing the actual arguments for \p F is to be created by + /// \c rosa::deluxe::DeluxeAgent::prepareCurrentInputs. + /// + /// \tparam T output type of the processing function + /// \tparam A type of the first mandatory input for the processing function + /// \tparam As types of further optional inputs for the processing function + /// \tparam S1 indices starting with `1` for extracting actual arguments from + /// \p Args + /// + /// \param F the processing function to invoke + /// \param Args the actual arguments to invoke \p F with + /// + /// \note The last argument provides indices statically as template arguments + /// \p S1..., so its actual value is ignored. + /// + /// \return the result of \p F for actual arguments \p Args + /// + /// \pre The provided sequence of indices \p S1... prefixed with the value + /// `0` constitutes a proper sequence for extracting all actual arguments for + /// \p F from \p Args: \code + /// sizeof...(As) == sizeof...(S1) + /// \endocde + template + static T + invokeWithTuple(D F, + std::tuple, std::pair...> Args, + Seq<0, S1...>) noexcept; + + /// Wraps a processing function into a trigger handler. + /// + /// \see \c rosa::deluxe::DeluxeAgent::FP + /// + /// \note The function cannot be const qualified because the lambda + /// expression defined in it needs to capture \p this object by a non-const + /// reference + /// + /// \tparam T type of output + /// \tparam A type of the first mandatory input value + /// \tparam As types of further optional input values + /// + /// \param F function processing inputs and generating output + /// + /// \pre Template arguments \p T, \p A and \p As... match the corresponding + /// types \p this object was created with: \code + /// OutputType == TypeNumberOf::Value && inputTypesMatch() + /// \endcode + template + H triggerHandlerFromProcessingFunction(D &&F) noexcept; + +public: + /// Creates a new instance. + /// + /// The constructor instantiates the base-class with functions to handle + /// messages as defined for the *deluxe interface*. + /// + /// \note Template argument deduction for this constructor breaks older Clang + /// versions, the minimal working version is 3.9.0. The issue and minimal + /// version requirement are recorded in the documentation. Using the named + /// constructor idiom was also investigated to no avail. Explicit + /// specification of actual template arguments does not stop Clang 3.8.0 from + /// breaking on a call to a corresponding named constructor. + /// + /// \tparam T type of output of \p F + /// \tparam A type of mandatory first input value of \p F + /// \tparam As types of further optional input values of \p F + /// + /// \note Instantiation fails if any of the type arguments \p T, \p A, and + /// \p As... is not a built-in type. + /// + /// \param Kind kind of the new \c rosa::Unit instance + /// \param Id unique identifier of the new \c rosa::Unit instance + /// \param Name name of the new \c rosa::Unit instance + /// \param S \c rosa::MessagingSystem owning the new instance + /// \param F function to process input values and generate output with + /// + /// \pre Statically, all of the type arguments \p T, \p A, and \p As... is a + /// built-in type: \code + /// TypeListSubsetOf, BuiltinTypes>::Value + /// \endcode Dynamically, the instance is created as of kind + /// \c rosa::deluxe::atoms::AgentKind: \code + /// Kind == rosa::deluxe::atoms::AgentKind + /// \endcode + template , BuiltinTypes>::Value>> + DeluxeAgent(const AtomValue Kind, const id_t Id, const std::string &Name, + MessagingSystem &S, D &&F) noexcept; + + /// Destroys \p this object. + ~DeluxeAgent(void) noexcept; + + /// The *master* of \p this object, if any is registered. + /// + /// \see \c rosa::deluxe::DeluxeAgent::registerMaster + /// + /// \return the *master* registered for \p this object + Optional master(void) const noexcept; + + /// Registers a *master* for \p this object. + /// + /// The new *master* is registered by overwriting the reference to any + /// already registered *master*. One can clear the registered reference by + /// passing an *empty* \c rosa::Optional object as actual argument. + /// + /// \note The role of the referred *master* is validated by checking its + /// *kind*. + /// + /// \param Master the *master* to register + /// + /// \pre \p Master is empty or of kind \c rosa::deluxe::atoms::AgentKind: + /// \code + /// !Master || unwrapAgent(*Master).Kind == rosa::deluxe::atoms::AgentKind + /// \endcode + void registerMaster(const Optional Master) noexcept; + + /// Tells the type of values consumed from the *slave* at a position. + /// + /// That is the type of values \p this object expect to be sent to it by its + /// *slave* registered at position \p Pos. + /// + /// \see \c rosa::deluxe::DeluxeAgent::slave + /// + /// \param Pos position of *slave* + /// + /// \return \c rosa::TypeNumber representing the type of values consumed from + /// the *slave* at position \p Pos + /// + /// \pre \p Pos is a valid index of input: \code + /// Pos < NumberOfInputs + /// \endcode + TypeNumber inputType(const size_t Pos) const noexcept; + + /// The *slave* of \p this object registered at a position, if any. + /// + /// \see \c rosa::deluxe::DeluxeAgent::registerSlave + /// + /// \param Pos position of *slave* + /// + /// \return the *slave* registered for \p this object at position \p Pos + /// + /// \pre \p Pos is a valid index of input: \code + /// Pos < NumberOfInputs + /// \endcode + Optional slave(const size_t Pos) const noexcept; + + /// Registers a *slave* for \p this object at a position. + /// + /// The new *slave* is registered by overwriting the reference to any already + /// registered *slave* at position \p Pos. One can clear the registered + /// reference by passing an *empty* \c rosa::Optional object as actual + /// argument. If \p Slave is already registered for another position, the + /// other position gets cleared. + /// + /// \note The role of the referred *slave* is validated by checking its + /// *kind*. + /// + /// \note The type of values produced by the referred *slave* is validated by + /// matching its `OutputType` against the corresponding value in + /// \c rosa::deluxe::DeluxeAgent::InputTypes. + /// + /// \param Pos position to register \p Slave at + /// \param Slave the *slave* to register + /// + /// \pre \p Pos is a valid index of input, \p Slave is empty or of kind + /// \c rosa::deluxe::atoms::AgentKind or \c rosa::deluxe::atoms::SensorKind, + /// and \p Slave -- if not empty -- produces values of types matching the + /// expected input type at position \p Pos: + /// \code + /// Pos < NumberOfInputs && + /// (!Slave || + /// (unwrapAgent(*Slave.)Kind == rosa::deluxe::atoms::SensorKind && + /// static_cast(unwrapAgent(*Slave)).OutputType == + /// InputTypes[Pos]) || + /// (unwrapAgent(*Slave).Kind == rosa::deluxe::atoms::AgentKind && + /// static_cast(unwrapAgent(*Slave)).OutputType == + /// InputTypes[Pos])) + /// \endcode + void registerSlave(const size_t Pos, + const Optional Slave) noexcept; + +private: + /// Sends a value to the *master* of \p this object. + /// + /// \p Value is getting sent to \c rosa::deluxe::DeluxeAgent::Master if it + /// contains a valid handle for a \c rosa::deluxe::DeluxeAgent. The function + /// does nothing otherwise. + /// + /// \tparam T type of the value to send + /// + /// \param Value value to send + /// + /// \pre \p T matches \c rosa::deluxe::DeluxeiAgent::OutputType: \code + /// OutputType == TypeNumberOf::Value + /// \endcode + template void sendToMaster(const T &Value) noexcept; + + /// Generates the next output by processing current input values upon trigger + /// from the system. + /// + /// Executes \c rosa::deluxe::DeluxeAgent::FP. + /// + /// \note The only argument is a \c rosa::AtomConstant, hence its actual + /// value is ignored. + void handleTrigger(atoms::Trigger) noexcept; + + /// Stores a new input value from a *slave*. + /// + /// The function stores \p Value in \c rosa::deluxe::DeluxeAgent::InputValues + /// at the position associated to \p Id in + /// \c rosa::deluxe::DeluxeAgent::SlaveIds and also sets the corresponding + /// flag in \c rosa::deluxe::DeluxeAgent::InputChanged. + /// + /// \note Utilized by member functions of group \c DeluxeAgentInputHandlers. + /// + /// \tparam T type of input to store + /// + /// \param Id unique identifier of *slave* + /// \param Value the input value to store + /// + /// \pre The *slave* with \p Id is registered and the input from it is + /// expected to be of type \p T: \code + /// SlaveIds.find(Id) != SlaveIds.end() && + /// InputTypes[SlaveIds.find(Id)->second] == TypeNumberOf::Value + /// \endcode + template void saveInput(id_t Id, T Value) noexcept; + + /// \defgroup DeluxeAgentInputHandlers + /// + /// Definition of member functions handling messages from *slaves* with + /// different types of input + /// + /// A *master* generally needs to be prepared to deal with values of any + /// built-in type. Each type requires a separate message handler, which are + /// implemented by these functions. The functions instantiate + /// \c rosa::deluxe::DeluxeAgent::saveInput with the proper template argument + /// and pass the content of the message on for processing. + /// + /// \note The member functions in this group are defined by \c DAHANDLERDEF. + /// + /// \note Keep these definitions in sync with \c rosa::BuiltinTypes. + /// + ///@{ + + DAHANDLERDEF(AtomValue) + DAHANDLERDEF(int16_t) + DAHANDLERDEF(int32_t) + DAHANDLERDEF(int64_t) + DAHANDLERDEF(int8_t) + DAHANDLERDEFN(long double, long_double) + DAHANDLERDEFN(std::string, std__string) + DAHANDLERDEF(uint16_t) + DAHANDLERDEF(uint32_t) + DAHANDLERDEF(uint64_t) + DAHANDLERDEF(uint8_t) + DAHANDLERDEF(unit_t) + DAHANDLERDEF(bool) + DAHANDLERDEF(double) + DAHANDLERDEF(float) + + /// @} + +}; + +/// Anonymous namespace with implementation for +/// \c rosa::deluxe::DeluxeAgent::inputTypesMatch, consider it private. +namespace { + +/// Template \c struct whose specializations provide a recursive implementation +/// for \c rosa::deluxe::DeluxeAgent::inputTypesMatch. +/// +/// \note Matching a list of types \p As... against a \c std::vector of +/// \c rosa::TypeNumber values, \c InputTypes, like \code +/// bool match = InputTypesMatchImpl::f(InputTypes, 0); +/// \endcode +/// +/// \tparam As types to match +template struct InputTypesMatchImpl; + +/// Template specialization for the general case, when at least one type is to +/// be matched. +/// +/// \tparam A first type to match +/// \tparam As further types to match +template struct InputTypesMatchImpl { + /// Tells whether types \p A, \p As... match \c rosa::TypeNumber values + /// stored in \p InputTypes starting at position \p Pos. + /// + /// The function has got a recursive implementation: it matches the first + /// type \p A against \c rosa::TypeNumber at position \p Pos of \p + /// InputTypes, then further types \p As.. are matched recursively starting + /// at position \c (Pos + 1). + /// + /// \param InputTypes container of \c rosa::TypeNumber values to match + /// types against + /// \param Pos position in \p InputTypes to start matching at + /// + /// \return if types \p A, \p As... match \c rosa::TypeNumber values stored + /// in \p InputTypes starting at position \p Pos + static bool f(const std::vector &InputTypes, + size_t Pos) noexcept { + return Pos < InputTypes.size() && + TypeNumberOf::Value == InputTypes[Pos] && + InputTypesMatchImpl::f(InputTypes, Pos + 1); + } +}; + +/// Template specialization for the terminal case, when no type remains to +/// check. +template <> struct InputTypesMatchImpl<> { + /// Tells whether \p Pos is the number of values stored in \p InputTypes. + /// + /// In this terminal case, there is no more types to matchi because all the + /// types are supposed to be already matched successfully. The whole list of + /// types already matched is a complete match if it covers all values in + /// \p InputTypes. That is true if \p Pos points exactly to the end of + /// \p InputTypes. + /// + /// \param InputTypes container of \c rosa::TypeNumber values to match + /// types against + /// \param Pos position in \p InputTypes to start matching at + /// + /// \return if \p Pos is the number of values stored in \p InputTypes + static bool f(const std::vector &InputTypes, + size_t Pos) noexcept { + return Pos == InputTypes.size(); + } +}; + +} // End namespace + +template +bool DeluxeAgent::inputTypesMatch(void) const noexcept { + return InputTypesMatchImpl::f(InputTypes, 0); +} + +template +std::tuple...> + DeluxeAgent::prepareCurrentInputs(Seq) const noexcept { + // Need to indirectly reference \c rosa::deluxe::DeluxeAgent::inputTypesMatch + // inside \c ASSERT because of the comma in its template argument list. + auto MFP = &DeluxeAgent::inputTypesMatch; + ASSERT(inv() && (this->*MFP)() && sizeof...(As) == sizeof...(S0)); + + return std::make_tuple( + std::make_pair(*static_cast(InputValues->pointerTo(S0)), + InputChanged[S0])...); +} + +template +T DeluxeAgent::invokeWithTuple( + D F, + std::tuple, std::pair...> Args, + Seq<0, S1...>) noexcept { + ASSERT(sizeof...(As) == sizeof...(S1)); + return F(std::get<0>(Args), std::get(Args)...); +} + +template +DeluxeAgent::H +DeluxeAgent::triggerHandlerFromProcessingFunction(D &&F) noexcept { + // Need to indirectly reference \c rosa::deluxe::DeluxeAgent::inputTypesMatch + // inside \c ASSERT because of the comma in its template argument list. + auto MFP = &DeluxeAgent::inputTypesMatch; + ASSERT(OutputType == TypeNumberOf::Value && (this->*MFP)()); + + return [this, F]() noexcept { + using Indices = typename GenSeq::Type; + auto Args = prepareCurrentInputs(Indices()); + std::fill(InputChanged.begin(), InputChanged.end(), false); + T R = invokeWithTuple(F, Args, Indices()); + sendToMaster(R); + }; +} + +template +DeluxeAgent::DeluxeAgent(const AtomValue Kind, const id_t Id, + const std::string &Name, MessagingSystem &S, + D &&F) noexcept + : Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger), + DAHANDLERREF(AtomValue), DAHANDLERREF(int16_t), + DAHANDLERREF(int32_t), DAHANDLERREF(int64_t), DAHANDLERREF(int8_t), + DAHANDLERREF(long_double), DAHANDLERREF(std__string), + DAHANDLERREF(uint16_t), DAHANDLERREF(uint32_t), + DAHANDLERREF(uint64_t), DAHANDLERREF(uint8_t), DAHANDLERREF(unit_t), + DAHANDLERREF(bool), DAHANDLERREF(double), DAHANDLERREF(float)), + OutputType(TypeNumberOf::Value), + NumberOfInputs(1 + sizeof...(As)), + InputTypes({TypeNumberOf::Value, TypeNumberOf::Value...}), + InputChanged(NumberOfInputs, false), + InputValues(new TokenizedStorage()), + FP(triggerHandlerFromProcessingFunction(std::move(F))), + Slaves(NumberOfInputs) { + ASSERT(Kind == atoms::AgentKind); + LOG_TRACE("DeluxeAgent is created."); + ASSERT(inv()); +} + +template +void DeluxeAgent::sendToMaster(const T &Value) noexcept { + ASSERT(inv() && OutputType == TypeNumberOf::Value); + + // There is a handle and the referred *master* is in a valid state. + if (Master && *Master) { + Master->sendMessage(Message::create(atoms::Slave::Value, Id, Value)); + } +} + +template void DeluxeAgent::saveInput(id_t Id, T Value) noexcept { + ASSERT(inv() && SlaveIds.find(Id) != SlaveIds.end() && + InputTypes[SlaveIds.find(Id)->second] == TypeNumberOf::Value); + + size_t Pos = SlaveIds.at(Id); + *static_cast(InputValues->pointerTo(Pos)) = Value; + InputChanged[Pos] = true; + + ASSERT(inv()); +} + + +} // End namespace deluxe +} // End namespace rosa + +#undef DAHANDLEREF +#undef DAHANDLEDEF +#undef DAHANDLEDEFN +#undef DAHANDLENAME + +#endif // ROSA_DELUXE_DELUXEAGENT_HPP diff --git a/include/rosa/deluxe/DeluxeAtoms.hpp b/include/rosa/deluxe/DeluxeAtoms.hpp new file mode 100755 index 0000000..d208f7d --- /dev/null +++ b/include/rosa/deluxe/DeluxeAtoms.hpp @@ -0,0 +1,61 @@ +//===-- rosa/deluxe/DeluxeAtoms.cpp -----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/deluxe/DeluxeAtoms.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Definition of \c rosa::AtomValue values and \c rosa::AtomConstant +/// types for the implementation of the *deluxe interface*. +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_DELUXE_DELUXEATOMS_HPP +#define ROSA_DELUXE_DELUXEATOMS_HPP + +#include "rosa/support/atom.hpp" + +namespace rosa { +namespace deluxe { + +/// Contains some definitions used in the implementation of the *deluxe +/// interface* to denote various roles and events +/// +/// \see \c rosa::deluxe::DeluxeContext +/// +/// \note Do not apply `using namespace` to this namespace as that may result in +/// some identifiers in the original namespace being hidden by those of +/// \c rosa::deluxe::atoms. +namespace atoms { + +/// Value to be used as the *kind* of \c rosa::deluxe::DeluxeSensor. +/// +/// \see \c rosa::Unit::Kind +constexpr AtomValue SensorKind = atom("dl_sensor"); + +/// Value to be used as the *kind* of \c rosa::deluxe::DeluxeAgent. +/// +/// \see \c rosa::Unit::Kind +constexpr AtomValue AgentKind = atom("dl_agent"); + +/// Type alias denoting system trigger messages. +using Trigger = AtomConstant; + +/// Type alias denoting messages from a slave. +using Slave = AtomConstant; + +/// Type alias denoting messages from a master. +/// +/// \note This one is not used at the moment. +using Master = AtomConstant; + +} // End namespace atoms +} // End namespace deluxe +} // End namespace rosa + +#endif // ROSA_DELUXE_DELUXEATOMS_HPP diff --git a/include/rosa/deluxe/DeluxeContext.hpp b/include/rosa/deluxe/DeluxeContext.hpp new file mode 100755 index 0000000..52e9a72 --- /dev/null +++ b/include/rosa/deluxe/DeluxeContext.hpp @@ -0,0 +1,282 @@ +//===-- rosa/deluxe/DeluxeContext.hpp ---------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/deluxe/DeluxeContext.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Public interface for the *deluxe interface* for working with agent +/// systems. +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_DELUXE_DELUXECONTEXT_HPP +#define ROSA_DELUXE_DELUXECONTEXT_HPP + +#include "rosa/deluxe/DeluxeSystem.hpp" + +#include "rosa/support/types.hpp" + +#include +#include +#include + +/// Local helper macro to log and return a +/// \c rosa::deluxe::DeluxeContext::ErrorCode value. +/// +/// Creates a debug message with the stringified value and returns the value. +/// +/// \param Err \c rosa::deluxe::DeluxeContext::ErrorCode value to log and +/// return +#define DCRETERROR(Err) \ + { \ + LOG_DEBUG(#Err); \ + return Err; \ + } + +namespace rosa { +namespace deluxe { + +/// Defines the *deluxe interface*. +class DeluxeContext { + + /// A system owned by \p this object. + /// + /// \note The reference is kept in a \c std::shared_ptr because of the member + /// function \c rosa::deluxe::DeluxeContext::getSystem. + std::shared_ptr System; + + /// References to all *sensors* and *agents* created by \p this object. + std::set DeluxeUnits; + +public: + + /// Errors that may be resulted by some of the member functions of the class. + enum struct ErrorCode { + NoError, + TypeMismatch, + NotSensor, + NotAgent, + WrongPosition, + AlreadyHasSlave, + AlreadyHasMaster, + AlreadyHasValueStream + }; + + /// Returns a new instance of \c rosa::deluxe::DeluxeContext. + /// + /// \param Name name of the underlying \c rosa::DeluxeSystem + /// + /// \return \c std::unique_ptr for the new instance of + /// \c rosa::deluxe::DeluxeContext with a new, empty \c rosa::DeluxeSystem + static std::unique_ptr + create(const std::string &Name) noexcept; + +private: + /// Creates a new instance. + /// + /// \note Private constructor restricts instantiation to member functions of + /// the class. + /// + /// \param Name name of the underlying \c rosa::MessagingSystem + DeluxeContext(const std::string &Name) noexcept; + +public: + /// Destroys \p this object. + ~DeluxeContext(void) noexcept; + + /// Returns a reference for the underlying \c rosa::MessagingSystem. + /// + /// \note One cannot do much with a \c rosa::MessagingSystem currently, this + /// is for future use. + /// + /// \return reference for the underlying \c rosa::MessagingSystem. + std::weak_ptr getSystem(void) const noexcept; + + /// Creates a new *sensor* in the context of \p this object. + /// + /// \tparam T type of data the new *sensor* operates on + /// + /// \param Name name of the new *sensor* + /// \param F function for the new *sensor* to generate the next value with + /// during normal operation + /// + /// \note \p F is not used during simulation, in which case + /// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to register + /// an alternative simulation data source with + /// \c rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may + /// safely keep relying on the default value of \p F as long as only + /// simulation of the system is to be done. + /// + /// \return \c rosa::AgentHandle for the new *sensor* + template + AgentHandle createSensor(const std::string &Name, + DeluxeSensor::D &&F = [](void) { + return T(); + }) noexcept; + + /// Creates a new *agent* in the context of \p this object. + /// + /// \tparam T type of data the new *agent* outputs + /// \tparam A type of mandatory first input the new *agent* takes + /// \tparam As types of futher optional inputs the new *agent* takes + /// + /// \param Name name of the new *agent* + /// \param F function for the new *agent* to process input values and + /// generate output with + /// + /// \return \c rosa::AgentHandle for the new *agent* + template + AgentHandle createAgent(const std::string &Name, + DeluxeAgent::D &&F) noexcept; + + /// Connectes a *sensor* to an *agent* in the context of \p this object. + /// + /// \param Agent the *agent* to connect to + /// \param Pos the index of slot of \p Agent to connect \p Sensor to + /// \param Sensor the *sensor* to connect + /// \param Description optional textual description of the connection + /// + /// \return how successfull connecting \p Sensor to \p Agent at slot index + /// \p Pos was + /// + /// \note The function may return the following + /// \c rosa::deluxe::DeluxeContext::ErrorCode values: + /// `ErrorCode` | Comment + /// ----------- | ------- + /// `NoError` | Success + /// `NotAgent` | Referred \p Agent is not \c rosa::deluxe::DeluxeAgent + /// `NotSensor` | Referred \p Sensor is not \c rosa::deluxe::DeluxeSensor + /// `WrongPosition` | \p Pos is not a valid input position of \p Agent + /// `TypeMismatch` | Expected input type at position \p Pos of \p Agent is other than the output type of \p Sensor + /// `AlreadyHasSlave` | \p Agent at position \p Pos already has a *slave* registered + /// `AlreadyHasMaster` | \p Sensor already has a *master* registered + ErrorCode connectSensor(AgentHandle &Agent, const size_t Pos, + AgentHandle &Sensor, + const std::string &Description = "") noexcept; + + /// Connectes two *agents* in the context of \p this object. + /// + /// \param Master the *agent* to connect to + /// \param Pos the index of slot of \p Master to connect \p Slave to + /// \param Slave the *agent* to connect + /// \param Description optional textual description of the connection + /// + /// \return how succesfull connecting \p Slave to \p Master at slot index + /// \p Pos was + /// + /// \note The function may return the following + /// \c rosa::deluxe::DeluxeContext::ErrorCode values: + /// `ErrorCode` | Comment + /// ----------- | ------- + /// `NoError` | Success + /// `NotAgent` | Referred \p Master or \p Slave is not \c rosa::deluxe::DeluxeAgent + /// `WrongPosition` | \p Pos is not a valid input position of \p Master + /// `TypeMismatch` | Expected input type at position \p Pos of \p Master is other than the output type of \p Slave + /// `AlreadyHasSlave` | \p Master at position \p Pos already has a *slave* registered + /// `AlreadyHasMaster` | \p Slave already has a *master* registered + ErrorCode connectAgents(AgentHandle &Master, const size_t Pos, + AgentHandle &Slave, + const std::string &Description = "") noexcept; + + /// Initializes \c this object and others managed by \p this object for + /// setting up and performing simulation. + /// + /// \see \c rosa::deluxe::DeluxeContext::registerSensorValues, + /// \c rosa::deluxe::DeluxeContext::simulate + /// + /// Need to clear simulation data sources from all the *sensors*. + void initializeSimulation(void) noexcept; + + /// Registers a stream providing values for a *sensor* during simulation. + /// + /// \tparam T type of values \p Sensor is operating on + /// + /// \param Sensor the *sensor* to register values for + /// \param Start provides values for \p Sensor + /// \param End denotes the end of stream of values + /// \param Default value to be used when input stream is depleted during + /// simulation + /// + /// \return how successful registering \p Source for \p Sensor + /// + /// \note The function may return the following + /// \c rosa::deluxe::DeluxeContext::ErrorCode values: + /// `ErrorCode` | Comment + /// ----------- | ------- + /// `NoError` | Success + /// `TypeMismatch` | \p Sensor generates values of a type other than \p T + /// `NotSensor` | Referred \p Sensor is not \c rosa::deluxe::DeluxeSensor + /// `AlreadyHasValueStream` | \p Sensor already has simulation data source set + template + ErrorCode + registerSensorValues(AgentHandle Sensor, std::istream_iterator &&Start, + std::istream_iterator &&End, T Default = {}) noexcept; + + /// Performs the system contained by \p this object. + /// + /// The function performs \p NumCycles cycle of simulation. In each cycle, + /// all the *agents* and *sensors* registered in + /// \c rosa::deluxe::DeluxeContext::DeluxeUnits are trigged for execution. + /// + /// \param NumCycles number of cycles to perform + /// + /// \pre All the *sensors* in the system contained by \p this object generate + /// their output from simulation data sources. + void simulate(const size_t NumCycles) const noexcept; +}; + +template +AgentHandle DeluxeContext::createSensor(const std::string &Name, + DeluxeSensor::D &&F) noexcept { + return System->createSensor(Name, std::move(F)); +} + +template +AgentHandle +DeluxeContext::createAgent(const std::string &Name, + DeluxeAgent::D &&F) noexcept { + return System->createAgent(Name, std::move(F)); +} + +template +DeluxeContext::ErrorCode DeluxeContext::registerSensorValues( + AgentHandle Sensor, std::istream_iterator &&Start, + std::istream_iterator &&End, T Default) noexcept { + // Make sure preconditions are met. + if (!System->isDeluxeSensor(Sensor)) { + DCRETERROR(ErrorCode::NotSensor); + } + auto S = System->getDeluxeSensor(Sensor); + ASSERT(S); // Sanity check. + if (S->OutputType != TypeNumberOf::Value) { + DCRETERROR(ErrorCode::TypeMismatch); + } else if (S->simulationDataSourceIsSet()) { + DCRETERROR(ErrorCode::AlreadyHasValueStream); + } + + // Register input stream. + S->registerSimulationDataSource([&](void) noexcept { + if (Start != End) { + return *Start++; + } else { + return Default; + } + }); + return ErrorCode::NoError; +} + +} // End namespace deluxe +} // End namespace rosa + +// Undef local macro if not used in the corresponding implementation. +#ifndef ROSA_LIB_DELUXE_DELUXECONTEXT_CPP +#undef DCRETERROR +#endif + +#endif // ROSA_DELUXE_DELUXECONTEXT_HPP diff --git a/include/rosa/deluxe/DeluxeSensor.hpp b/include/rosa/deluxe/DeluxeSensor.hpp new file mode 100755 index 0000000..9e4b61d --- /dev/null +++ b/include/rosa/deluxe/DeluxeSensor.hpp @@ -0,0 +1,250 @@ +//===-- rosa/deluxe/DeluxeSensor.hpp ----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/deluxe/DeluxeSensor.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Specialization of \c rosa::Agent for *sensor* role of the the *deluxe +/// interface*. +/// +/// \see \c rosa::deluxe::DeluxeContext +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_DELUXE_DELUXESENSOR_HPP +#define ROSA_DELUXE_DELUXESENSOR_HPP + +#include "rosa/core/Agent.hpp" + +#include "rosa/deluxe/DeluxeAtoms.hpp" + +namespace rosa { +namespace deluxe { + +/// Specialization of \c rosa::Agent for *sensor* role of the *deluxe +/// interface*. +/// +/// \see \c rosa::deluxe::DeluxeContext +class DeluxeSensor : public Agent { +public: + /// Template alias for function objects used as data source for + /// \c rosa::deluxe::DeluxeSensor. + /// + /// \tparam T type of data provided by the function + template using D = std::function; + + /// The type of values produced by \p this object. + /// + /// That is the type of values \p this object sends to its *master*. + /// + /// \see \c rosa::deluxe::DeluxeSensor::master + const TypeNumber OutputType; + +private: + + /// Alias for function objects used as trigger handler for + /// \c rosa::deluxe::DeluxeSensor. + /// + /// \see \c DeluxeSensorTriggerHandlers + using H = std::function; + + /// \defgroup DeluxeSensorTriggerHandlers + /// + /// \brief Trigger handler functions of \c rosa::deluxe::DeluxeSensor + /// + /// The actual data source functions are captured in a lambda expression that + /// is in turn wrapped in a \c std::function object. The lambda expression + /// calls the data source function to obtain the next sensory value and sends + /// it to *master* by calling \c rosa::deluxe::DeluxeSensor::sendToMaster. The + /// function \c rosa::deluxe::DeluxeSensor::handleTrigger needs only to call + /// the proper function object. + + /// Handles trigger during normal execution. + /// + /// \ingroup DeluxeSensorTriggerHandlers + /// + /// The function is used during normal execution. During simulation, the + /// simulation environment sets \c rosa::deluxe::DeluxeSensor::SFP, which is + /// used instead of \c rosa::deluxe::DeluxeSensor::FP. + const H FP; + + /// Handles trigger during simulation. + /// + /// \ingroup DeluxeSensorTriggerHandlers + /// + /// The function is empty by default. The simulation environment sets it to be + /// used during simulation. + H SFP; + + /// The *master* to send values to. + /// + /// \note *Masters* are set dynamically, hence it is possible that a + /// \c rosa::deluxe::DeluxeSensor instance does not have any *master* at a + /// given moment. + Optional Master; + + /// Wraps a data source function into a trigger handler. + /// + /// \see \c DeluxeSensorTriggerHandlers + /// + /// \tparam T type of data provided by \p F + /// + /// \param F function to generate value with + /// + /// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code + /// OutputType == TypeNumberOf::Value + /// \endcode + template + H triggerHandlerFromDataSource(D &&F) const noexcept; + +public: + /// Creates a new instance. + /// + /// The constructor instantiates the base-class with functions to handle + /// messages as defined for the *deluxe interface*. + /// + /// \tparam T type of data to operate on + /// + /// \param Kind kind of the new \c rosa::Unit instance + /// \param Id unique identifier of the new \c rosa::Unit instance + /// \param Name name of the new \c rosa::Unit instance + /// \param S \c rosa::MessagingSystem owning the new instance + /// \param F function to generate the next value with during normal operation + /// + /// \pre Statically \code + /// TypeListContains::Value + /// \endcode Dynamically, the instance is created as of kind + /// \c rosa::deluxe::atoms::SensorKind \code + /// Kind == rosa::deluxe::atoms::SensorKind + /// \endcode + template ::Value>> + DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name, + MessagingSystem &S, D &&F) noexcept; + + /// Destroys \p this object. + ~DeluxeSensor(void) noexcept; + + /// The *master* of \p this object, if any. + /// + /// \see \c rosa::deluxe::DeluxeSensor::registerMaster + /// + /// \return the *master* registered for \p this object + Optional master(void) const noexcept; + + /// Registers a *master* for \p this object. + /// + /// The new *master* is registered by overwriting the reference to any + /// already registered *master*. One can clear the registered reference by + /// passing an *empty* \c rosa::Optional object as actual argument. + /// + /// \note The role of the referred *master* is validated by checking its + /// *kind*. + /// + /// \param Master the *master* to register + /// + /// \pre \p Master is empty or of kind \c rosa::deluxe::atoms::AgentKind: + /// \code + /// !Master || unwrapAgent(*Master).Kind == rosa::deluxe::atoms::AgentKind + /// \code + void registerMaster(const Optional Master) noexcept; + + /// Clears the simulation trigger handler of \p this object. + /// + /// The function assigns \c rosa::deluxe::DeluxeSensor::SFP with \c nullptr. + void clearSimulationDataSource(void) noexcept; + + /// Tells whether a simulation trigger handler is set for \p this object. + /// + /// The function returns whether \c rosa::deluxe::DeluxeSensor::SFP is not + /// \c nullptr. + /// + /// \return if a simulation trigger handler is set for \p this object. + bool simulationDataSourceIsSet(void) const noexcept; + + /// Registers a simulation data source for \p this object. + /// + /// A new simulation trigger handler wrapping \p SF is stored in + /// \c rosa::deluxe::DeluxeSensor::SFP by overwriting any already registered + /// simulation data source. + /// + /// \tparam T type of data provided by \p SF + /// + /// \param SF function to generate value with + /// + /// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code + /// OutputType == TypeNumberOf::Value + /// \endcode + template void registerSimulationDataSource(D &&SF) noexcept; + +private: + /// Sends a value to the *master* of \p this object. + /// + /// \p Value is getting sent to \c rosa::deluxe::DeluxeSensor::Master if it + /// contains a valid handle for a \c rosa::deluxe::DeluxeAgent. The function + /// does nothing otherwise. + /// + /// \tparam T type of the value to send + /// + /// \param Value value to send + /// + /// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code + /// OutputType == TypeNumberOf::Value + /// \endcode + template void sendToMaster(const T &Value) noexcept; + + /// Generates the next sensory value upon trigger from the system. + /// + /// Executes \c rosa::deluxe::DeluxeSensor::FP or + /// \c rosa::deluxe::DeluxeSensor::SFP if set. + /// + /// \note The only argument is a \c rosa::AtomConstant, hence its actual + /// value is ignored. + void handleTrigger(atoms::Trigger) noexcept; +}; + +template +DeluxeSensor::H DeluxeSensor::triggerHandlerFromDataSource(D &&F) const + noexcept { + ASSERT(OutputType == TypeNumberOf::Value); + return [this, F](void) noexcept { sendToMaster(F()); }; +} + +template +DeluxeSensor::DeluxeSensor(const AtomValue Kind, const id_t Id, + const std::string &Name, MessagingSystem &S, + D &&F) noexcept + : Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger)), + OutputType(TypeNumberOf::Value), + FP(triggerHandlerFromDataSource(std::move(F))), + SFP(nullptr) { + ASSERT(Kind == atoms::SensorKind); + LOG_TRACE("DeluxeSensor is created."); +} + +template +void DeluxeSensor::registerSimulationDataSource(D &&SF) noexcept { + ASSERT(OutputType == TypeNumberOf::Value); + SFP = triggerHandlerFromDataSource(std::move(SF)); +} + +template +void DeluxeSensor::sendToMaster(const T &Value) noexcept { + ASSERT(OutputType == TypeNumberOf::Value); + + // There is a handle and the referred *master* is in a valid state. + if (Master && *Master) { + Master->sendMessage(Message::create(atoms::Slave::Value, Id, Value)); + } +} + +} // End namespace deluxe +} // End namespace rosa + +#endif // ROSA_DELUXE_DELUXESENSOR_HPP diff --git a/include/rosa/deluxe/DeluxeSystem.hpp b/include/rosa/deluxe/DeluxeSystem.hpp new file mode 100755 index 0000000..56dcf3c --- /dev/null +++ b/include/rosa/deluxe/DeluxeSystem.hpp @@ -0,0 +1,213 @@ +//===-- rosa/deluxe/DeluxeSystem.hpp ----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/deluxe/DeluxeSystem.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Specialization of \c rosa::MessagingSystem for the *deluxe +/// interface*. +/// +/// \see \c rosa::deluxe::DeluxeContext +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_DELUXE_DELUXESYSTEM_HPP +#define ROSA_DELUXE_DELUXESYSTEM_HPP + +#include "rosa/core/MessagingSystem.hpp" + +#include "rosa/deluxe/DeluxeAgent.hpp" +#include "rosa/deluxe/DeluxeSensor.hpp" + +namespace rosa { +namespace deluxe { + +/// Implements and extends the \c rosa::MessagingSystem interface to be +/// used by \c rosa::deluxe::DeluxeContext. +/// +/// The class is a specialization of \c rosa::MessagingSystem, where objects +/// of two specialized subtypes of \c rosa::Agent, \c rosa::deluxe::DeluxeSensor +/// and \c rosa::deluxe::DeluxeAgent, constitute a system. The class extends the +/// \c rosa::MessagingSystem interface with features required to implement the +/// *deluxe interface*. +/// +/// \see rosa::deluxe::DeluxeContext +class DeluxeSystem : public MessagingSystem { + + friend class DeluxeContext; + +public: + /// Returns an object implementing the \c rosa::deluxe::DeluxeSystem + /// interface. + /// + /// \param Name name of the new instance + /// + /// \return \c std::unique_ptr for the new instance of + /// \c rosa::DeluxeSystem + static std::unique_ptr + createSystem(const std::string &Name) noexcept; + +protected: + /// Creates a new instance. + /// + /// \note Protected constructor restricts instantiation for subclasses. + DeluxeSystem(void) noexcept = default; + +public: + /// Creates a \c rosa::deluxe::DeluxeSensor instance owned by \p this object + /// and returns a \p rosa::AgentHandle for it. + /// + /// \tparam T type of data the new \c rosa::deluxe::DeluxeSensor operates on + /// + /// \param Name name of the new \c rosa::deluxe::DeluxeSensor + /// \param F function to generate the next value with during normal operation + /// + /// \return \c rosa::AgentHandle for new \c rosa::deluxe::DeluxeSensor + template + AgentHandle createSensor(const std::string &Name, + DeluxeSensor::D &&F) noexcept; + + /// Creates a \c rosa::deluxe::DeluxeAgent instance owned by \p this object + /// and returns a \c rosa::AgentHandle for it. + /// + /// \tparam T type of data the new \c rosa::deluxe::DeluxeAgent outputs + /// \tparam A type of mandatory first input the new + /// \c rosa::deluxe::DeluxeAgent takes + /// \tparam As types of futher optional inputs the new + /// \c rosa::deluxe::DeluxeAgent takes + /// + /// \param Name name of the new \c rosa::deluxe::DeluxeAgent + /// \param F function for the new \c rosa::deluxe::DeluxeAgent to process + /// input values and generate output with + /// + /// \return \c rosa::AgentHandle for new \c rosa::deluxe::DeluxeAgent + template + AgentHandle createAgent(const std::string &Name, + DeluxeAgent::D &&F) noexcept; + +protected: + /// Tells whether a \c rosa::AgentHandle refers to a + /// \c rosa::deluxe::DeluxeSensor owned by \p this object. + /// + /// \param H \c rosa::AgentHandle to check + /// + /// \return whether \p H refers to a \c rosa::deluxe::DeluxeSensor owned by + /// \p this object + virtual bool isDeluxeSensor(const AgentHandle &H) const noexcept = 0; + + /// Extracts a const qualified \c rosa::deluxe::DeluxeSensor reference from a + /// const qualified \c rosa::AgentHandle if possible. + /// + /// The function returns a \c rosa::Optional object containing a const + /// qualified reference to a \c rosa::deluxe::DeluxeSensor object extracted + /// from a const qualified \c rosa::AgentHandle instance if the referred + /// object is of type \c rosa::deluxeDeluxeSensor and owned by \p this object. + /// The returned \c rosa::Optional object is empty otherwise. + /// + /// \see rosa::deluxe::DeluxeSystem::isDeluxeSensor + /// + /// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeSensor + /// from + /// + /// \return const qualified reference to \c rosa::deluxe::DeluxeSensor if + /// \p H refers to an object which is of that type and is owned by \p this + /// object + Optional getDeluxeSensor(const AgentHandle &H) const + noexcept; + + /// Extracts a \c rosa::deluxe::DeluxeSensor reference from a + /// \c rosa::AgentHandle if possible. + /// + /// The function returns a \c rosa::Optional object containing a reference to + /// a \c rosa::deluxe::DeluxeSensor object extracted from a + /// \c rosa::AgentHandle instance if the referred object is of type + /// \c rosa::deluxeDeluxeSensor and owned by \p this object. The returned + /// \c rosa::Optional object is empty otherwise. + /// + /// \see rosa::deluxe::DeluxeSystem::isDeluxeSensor + /// + /// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeSensor + /// from + /// + /// \return reference to \c rosa::deluxe::DeluxeSensor if \p H refers to an + /// object which is of that type and is owned by \p this object + Optional getDeluxeSensor(AgentHandle &H) const noexcept; + + /// Tells whether a \c rosa::AgentHandle refers to a + /// \c rosa::deluxe::DeluxeAgent owned by \p this object. + /// + /// \param H \c rosa::AgentHandle to check + /// + /// \return whether \p H refers to a \c rosa::deluxe::DeluxeAgent owned by + /// \p this object + virtual bool isDeluxeAgent(const AgentHandle &H) const noexcept = 0; + + /// Extracts a const qualified \c rosa::deluxe::DeluxeAgent reference from a + /// const qualified \c rosa::AgentHandle if possible. + /// + /// The function returns a \c rosa::Optional object containing a const + /// qualified reference to a \c rosa::deluxe::DeluxeAgent object extracted + /// from a const qualified \c rosa::AgentHandle instance if the referred + /// object is of type \c rosa::deluxeDeluxeAgent and owned by \p this object. + /// The returned \c rosa::Optional object is empty otherwise. + /// + /// \see rosa::deluxe::DeluxeSystem::isDeluxeAgent + /// + /// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeAgent + /// from + /// + /// \return const qualified reference to \c rosa::deluxe::DeluxeAgent if \p H + /// refers to an object which is of that type and is owned by \p this object + Optional getDeluxeAgent(const AgentHandle &H) const + noexcept; + + /// Extracts a \c rosa::deluxe::DeluxeAgent reference from a + /// \c rosa::AgentHandle if possible. + /// + /// The function returns a \c rosa::Optional object containing a reference to + /// a \c rosa::deluxe::DeluxeAgent object extracted from a + /// \c rosa::AgentHandle instance if the referred object is of type + /// \c rosa::deluxeDeluxeAgent and owned by \p this object. The returned + /// \c rosa::Optional object is empty otherwise. + /// + /// \see rosa::deluxe::DeluxeSystem::isDeluxeAgent + /// + /// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeAgent + /// from + /// + /// \return reference to \c rosa::deluxe::DeluxeAgent if \p H refers to an + /// object which is of that type and is owned by \p this object + Optional getDeluxeAgent(AgentHandle &H) const noexcept; +}; + +template +AgentHandle DeluxeSystem::createSensor(const std::string &Name, + DeluxeSensor::D &&F) noexcept { + Agent &DS = createUnit([&]( + const id_t Id, MessagingSystem &S) noexcept { + return new DeluxeSensor(atoms::SensorKind, Id, Name, S, std::move(F)); + }); + return {DS}; +} + +template +AgentHandle +DeluxeSystem::createAgent(const std::string &Name, + DeluxeAgent::D &&F) noexcept { + Agent &DA = createUnit([&]( + const id_t Id, DeluxeSystem &S) noexcept { + return new DeluxeAgent(atoms::AgentKind, Id, Name, S, std::move(F)); + }); + return {DA}; +} + +} // End namespace deluxe +} // End namespace rosa + +#endif // ROSA_LIB_DELUXE_DELUXESYSTEM_HPP diff --git a/include/rosa/deluxe/namespace.h b/include/rosa/deluxe/namespace.h new file mode 100755 index 0000000..58f8e7b --- /dev/null +++ b/include/rosa/deluxe/namespace.h @@ -0,0 +1,32 @@ +//===-- rosa/deluxe/namespace.h ---------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/deluxe/namespace.h +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Documentation for the namespace \c rosa::deluxe. +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_DELUXE_NAMESPACE_H +#define ROSA_DELUXE_NAMESPACE_H + +namespace rosa { + +/// Contains a simplified, limited in functionality but flexible in modularity, +/// interface to define and easily reconfigure agent systems. +/// +/// **Deluxe Interface** +/// +/// TODO write this description here! +namespace deluxe {} + +} // End namespace rosa + +#endif // ROSA_DELUXE_NAMESPACE_H diff --git a/include/rosa/support/sequence.hpp b/include/rosa/support/sequence.hpp new file mode 100755 index 0000000..7d7e082 --- /dev/null +++ b/include/rosa/support/sequence.hpp @@ -0,0 +1,49 @@ +//===-- rosa/support/sequence.hpp -------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/support/sequence.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Template facilities to statically generate a sequence of numbers. +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_SUPPORT_SEQUENCE_HPP +#define ROSA_SUPPORT_SEQUENCE_HPP + +#include + +namespace rosa { + +/// \defgroup Seq +/// +///@{ + +/// Template with an empty struct to store a sequence of numbers in compile time +/// as template arguments. +/// +/// Generate a sequence of numbers from `0` up to (including) `(N - 1)` like +/// \code +/// typename GenSeq::Type +/// \endcode +template struct Seq {}; + +/// Sequence generator, the general case when counting down by extending the +/// sequence. +template struct GenSeq : GenSeq {}; + +/// Sequence generator, the terminal case when storing the generated sequence +/// into \c Seq. +template struct GenSeq<0, S...> { using Type = Seq; }; + +///@} + +} // End namespace rosa + +#endif // ROSA_SUPPORT_SEQUENCE_HPP diff --git a/include/rosa/support/tokenized_storages.hpp b/include/rosa/support/tokenized_storages.hpp new file mode 100755 index 0000000..d52f233 --- /dev/null +++ b/include/rosa/support/tokenized_storages.hpp @@ -0,0 +1,508 @@ +//===-- rosa/support/tokenized_storages.hpp ---------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/support/tokenized_storages.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Definition of storage helper template for storing values in a +/// type-safe way based on type tokens. +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_SUPPORT_TOKENIZED_STORAGES_HPP +#define ROSA_SUPPORT_TOKENIZED_STORAGES_HPP + +#include "rosa/support/type_token.hpp" + +#include +#include + +namespace rosa { + +/// Defines a simple interface for storing and accessing values of different +/// types. +/// +/// While the interface provides features to access values and know their +/// types, it is the users responsibility to use particular values according to +/// their actual types. No facilities for type-safe access of values is +/// provided by the class. +/// +/// \see \c rosa::TokenizedStorage for a type-safe specialization of the +/// interface. +class AbstractTokenizedStorage { +protected: + /// Protected constructor restricts instantiation for derived classes. + AbstractTokenizedStorage(void) noexcept = default; + +public: + /// No copying and moving of \c rosa::AbstractTokenizedStorage instances. + ///@{ + AbstractTokenizedStorage(const AbstractTokenizedStorage&) = delete; + AbstractTokenizedStorage &operator=(const AbstractTokenizedStorage&) = delete; + AbstractTokenizedStorage(AbstractTokenizedStorage&& Other) = delete; + AbstractTokenizedStorage &operator=(AbstractTokenizedStorage&&) = delete; + ///@} + + /// Destroys \p this object. + virtual ~AbstractTokenizedStorage(void) noexcept = default; + + /// Tells how many values are stored in \p this object. + /// + /// \return number of values stored in \p this object + virtual size_t size(void) const noexcept = 0; + + /// Tells the type of the value stored at a position. + /// + /// \param Pos the index of the value whose type is to returned + /// + /// \return \c rosa::TypeNumber for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < size() + /// \endcode + virtual TypeNumber typeAt(const size_t Pos) const noexcept = 0; + + /// Provides an untyped pointer for the value stored at a position. + /// + /// \param Pos the index of the value to return an untyped pointer for + /// + /// \return untyped pointer for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < size() + /// \endcode + virtual void *pointerTo(const size_t Pos) noexcept = 0; + + /// Provides a constant untyped pointer for the value stored at a position. + /// + /// \param Pos the index of the value to return an untyped pointer for + /// + /// \return constant untyped pointer for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < Offsets.size() + /// \endcode + virtual const void *pointerTo(const size_t Pos) const noexcept = 0; +}; + +/// Template class storing values and providing dynamic type-safe access to +/// them in a lightweight way based on type tokens. +/// +/// \see rosa/support/type_token.hpp +/// +/// \tparam Types types whose values are to be stored +template class TokenizedStorage; + +/// Nested namespace with implementation for \c rosa::TokenizedStorage, consider +/// it private. +namespace { + +/// Initializes a pre-allocated memory area with values from constant lvalue +/// references. +/// +/// \tparam Types types whose values are to be stored +/// +/// \param Arena pre-allocated memory area to store values to +/// \param Ts the values to store in \p Arena +/// +/// \note \p Arena needs to be a valid pointer to a memory area big enough for +/// values of \p Types. +template +inline void createArenaElements(void *const Arena, + const Types &... Ts) noexcept; + +/// \defgroup createArenaElement from const lvalue references +/// +/// Stores values from constant lvalue references into a pre-allocated memory +/// area. +/// +/// \note To be used by the implementation of \c createArenaElements. +/// +/// \todo Document these functions. +///@{ + +/// \note This terminal case is used for both constant lvalue references and +/// value references. +template +inline void createArenaElement(void *const, + const std::vector &Offsets) { + ASSERT(Pos == Offsets.size()); +} + +template +inline void createArenaElement(void *const Arena, + const std::vector &Offsets, + const Type &T, const Types &... Ts) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + new (static_cast(static_cast(static_cast(Arena) + + Offsets[Pos]))) Type(T); + createArenaElement(Arena, Offsets, Ts...); +} + +template +inline void +createArenaElement(void *const Arena, const std::vector &Offsets, + const AtomConstant &, const Types &... Ts) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + *static_cast( + static_cast(static_cast(Arena) + Offsets[Pos])) = V; + createArenaElement(Arena, Offsets, Ts...); +} + +///@} + +/// Implementation of the template. +/// +/// \tparam Type the type of the mandatory first value to store +/// \tparam Types types of any further values to store +/// +/// \param Arena pre-allocated memory area to store values to +/// \param T the first value to store in \p ArenaË› +/// \param Ts optional further values to store in \p Arena +/// +/// \pre \p Arena is not \p nullptr. +template +inline void createArenaElements(void *const Arena, const Type &T, + const Types &... Ts) noexcept { + ASSERT(Arena != nullptr); + createArenaElement<0>(Arena, TokenizedStorage::Offsets, T, + Ts...); +} + +/// Initializes a pre-allocated memory area with values from rvalue references. +/// +/// \tparam Types types whose values are to be stored +/// +/// \param Arena pre-allocated memory area to store values to +/// \param Ts the values to store in \p Arena +/// +/// \note \p Arena needs to be a valid pointer to a memory area big enough for +/// values of \p Types. +template +inline void createArenaElements(void *const Arena, Types &&... Ts) noexcept; + +/// \defgroup createArenaElement from rvalue references +/// +/// Stores values from rvalue references into a pre-allocated memory area. +/// +/// \note To be used by the implementation of \c createArenaElements. +/// +/// \todo Document these functions. +///@{ + +template +inline void createArenaElement(void *const Arena, + const std::vector &Offsets, Type &&T, + Types &&... Ts) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + new (static_cast(static_cast( + static_cast(Arena) + Offsets[Pos]))) Type(std::move(T)); + createArenaElement(Arena, Offsets, std::move(Ts)...); +} + +template +inline void createArenaElement(void *const Arena, + const std::vector &Offsets, + AtomConstant &&, Types &&... Ts) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + *static_cast( + static_cast(static_cast(Arena) + Offsets[Pos])) = V; + createArenaElement(Arena, Offsets, std::move(Ts)...); +} + +///@} + +/// Implementation of the template. +/// +/// \tparam Type the type of the mandatory first value to store +/// \tparam Types types of any further values to store +/// +/// \param Arena pre-allocated memory area to store values to +/// \param T the first value to store in \p Arena +/// \param Ts optional further values to store in \p Arena +/// +/// \pre \p Arena is not \c nullptr. +template +inline void createArenaElements(void *const Arena, Type &&T, + Types &&... Ts) noexcept { + ASSERT(Arena != nullptr); + createArenaElement<0>(Arena, TokenizedStorage::Offsets, + std::move(T), std::move(Ts)...); +} + +/// Destroys values allocated by \c createArenaElements. +/// +/// \tparam Type type of the mandatory first value stored in \p Arena +/// \tparam Types futher types whose values are stored in \p Arena +/// +/// \param Arena the memory area to destroy values from +/// +/// \note \p Arena needs to be a valid pointer to a memory area where values of +/// \p Types are stored. +template +inline void destroyArenaElements(void *const Arena) noexcept; + +/// \defgroup destroyArenaElement +/// +/// Destroys values from a memory area. +/// +/// \note To be used by the implementation of \c destroyArenaElements. +/// +/// \todo Document these functions. +///@{ + +template +inline void destroyArenaElement(void *const, + const std::vector &Offsets) noexcept { + ASSERT(Pos == Offsets.size()); +} + +template +inline void destroyArenaElement(void *const Arena, + const std::vector &Offsets) noexcept { + ASSERT(Arena != nullptr && Pos < Offsets.size()); + static_cast( + static_cast(static_cast(Arena) + Offsets[Pos])) + ->~Type(); + destroyArenaElement(Arena, Offsets); +} + +///@} + +/// Implementation of the template. +/// +/// \tparam Type the type of the mandatory first value to destroy +/// \tparam Types types of any further values to destroy +/// +/// \param Arena the memory area to destroy values from +/// +/// \pre \p Arena is not \c nullptr. +template +inline void destroyArenaElements(void *const Arena) noexcept { + ASSERT(Arena != nullptr); + destroyArenaElement<0, Type, Types...>( + Arena, TokenizedStorage::Offsets); +} + +} // End namespace + +/// Implementation of the template \c rosa::TokenizedStorage as a +/// specialization of \c rosa::AbstractTokenizedStorage. +/// +/// The class provides facilities for storing values and providing type-safe +/// access to them. +/// +/// \tparam Type type of the first mandatory value to store +/// \tparam Types of any further values to store +template +class TokenizedStorage : public AbstractTokenizedStorage { +public: + /// \c rosa::Token for the stored values. + static constexpr Token ST = + TypeToken::type, + typename std::decay::type...>::Value; + + /// Byte offsets to access stored values in \c rosa::TokenizedStorage::Arena. + static const std::vector Offsets; + +private: + /// A BLOB storing all the values one after the other. + void *const Arena; + + /// Generates byte offsets for accessing values stored in + /// \c rosa::TokenizedStorage::Arena. + /// + /// \return \c std::vector containing byte offsets for accessing values stored + /// in \c rosa::TokenizedStorage::Arena + static std::vector offsets(void) noexcept { + Token T = ST; // Need a mutable copy. + const size_t N = lengthOfToken(T); // Number of types encoded in \c T. + size_t I = 0; // Start indexing from position \c 0. + std::vector O(N); // Allocate vector of proper size. + O[0] = 0; // First offset is always \c 0. + while (I < N - 1) { + ASSERT(I + 1 < O.size() && lengthOfToken(T) == N - I); + // Calculate next offset based on the previous one. + // \note The offset of the last value is stored at `O[N - 1]`, which is + // set when `I == N - 2`. Hence the limit of the loop. + O[I + 1] = O[I] + sizeOfHeadOfToken(T); + dropHeadOfToken(T), ++I; + } + ASSERT(I + 1 == O.size() && lengthOfToken(T) == 1); + return O; + } + +public: + /// Creates an instance with default values. + /// + /// \note This constructor requires that all actual template arguments \c Type + /// and \c Types... are default constructible. + TokenizedStorage(void) noexcept + : Arena(::operator new(sizeOfValuesOfToken(ST))) { + ASSERT(Arena != nullptr); // Sanity check. + createArenaElements(Arena, Type(), Types()...); + } + + /// Creates an instance from constant lvalue references. + /// + /// \param T the mandatory first value to store + /// \param Ts optional further values to store + TokenizedStorage(const Type &T, const Types &... Ts) noexcept + : Arena(::operator new(sizeOfValuesOfToken(ST))) { + ASSERT(Arena != nullptr); // Sanity check. + createArenaElements(Arena, T, Ts...); + } + + /// Creates an instance from rvalue references. + /// + /// \param T the mandatory first value to store + /// \param Ts optional further values to store + TokenizedStorage(Type &&T, Types &&... Ts) noexcept + : Arena(::operator new(sizeOfValuesOfToken(ST))) { + ASSERT(Arena != nullptr); // Sanity check. + createArenaElements(Arena, std::move(T), std::move(Ts)...); + } + + /// No copying and moving of \c rosa::TokenizedStorage instances. + /// + /// \note This restriction may be relaxed as moving should be easy to + /// implement, only requires the possiblity to validate Arena pointer. + ///@{ + TokenizedStorage(const TokenizedStorage&) = delete; + TokenizedStorage &operator=(const TokenizedStorage&) = delete; + TokenizedStorage(TokenizedStorage&& Other) = delete; + TokenizedStorage &operator=(TokenizedStorage&&) = delete; + ///@} + + // Destroys \p this object. + ~TokenizedStorage(void) { + destroyArenaElements(Arena); + ::operator delete(Arena); + } + + /// Tells how many values are stored in \p this object. + /// + /// \return number of values stored in \p this object + size_t size(void) const noexcept override { + return Offsets.size(); + } + + /// Tells the type of the value stored at a position. + /// + /// \param Pos the index of the value whose type is to returned + /// + /// \return \c rosa::TypeNumber for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < size() + /// \endcode + TypeNumber typeAt(const size_t Pos) const noexcept override { + ASSERT(Pos < size()); + Token TT = ST; + dropNOfToken(TT, Pos); + return headOfToken(TT); + } + + /// Provides an untyped pointer for the value stored at a position. + /// + /// \param Pos the index of the value to return an untyped pointer for + /// + /// \return untyped pointer for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < size() + /// \endcode + void *pointerTo(const size_t Pos) noexcept override { + ASSERT(Pos < size()); + return static_cast(Arena) + Offsets[Pos]; + } + + /// Provides a constant untyped pointer for the value stored at a position. + /// + /// \param Pos the index of the value to return an untyped pointer for + /// + /// \return constant untyped pointer for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index:\code + /// Pos < Offsets.size() + /// \endcode + const void *pointerTo(const size_t Pos) const noexcept override { + ASSERT(Pos < size()); + return static_cast(Arena) + Offsets[Pos]; + } + + /// Tells if the value stored at a given index is of a given type. + /// + /// \note Any \c rosa::AtomConstant is encoded in \c rosa::Token as + /// the \c rosa::AtomValue wrapped into it. + /// + /// \tparam T type to match against + /// + /// \param Pos index the type of the value at is to be matched against \p Type + /// + /// \return if the value at index \p Pos of type \p T + /// + /// \pre \p Pos is a valid index:\code + /// Pos < Offsets.size() + /// \endcode + template bool isTypeAt(const size_t Pos) const noexcept { + ASSERT(Pos < size()); + Token TT = ST; + dropNOfToken(TT, Pos); + return isHeadOfTokenTheSameType(TT); + } + + /// Gives a reference of a value of a given type stored at a given index. + /// + /// \note The constant variant of the function relies on this implementation, + /// the function may not modify \p this object! + /// + /// \tparam T type to give a reference of + /// + /// \param Pos index to set the reference for + /// + /// \return reference of \p Type for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index and the value at index \p Pos is of type + /// \p T:\code + /// Pos < Size && isTypeAt(Pos) + /// \endcode + template Type &valueAt(const size_t Pos) noexcept { + ASSERT(Pos < size() && isTypeAt(Pos)); + return *static_cast(pointerTo(Pos)); + } + + /// Gives a constant reference of a value of a given type stored at a given + /// index. + /// + /// \tparam T type to give a reference of + /// + /// \param Pos index to set the reference for + /// + /// \return constant reference of \p Type for the value stored at index \p Pos + /// + /// \pre \p Pos is a valid index and the value at index \p Pos is of type + /// \p T:\code + /// Pos < Size && isTypeAt(Pos) + /// \endcode + template const Type &valueAt(const size_t Pos) const noexcept { + // \note Just use the non-const implementation as that does not modify + // \p this object. + return const_cast(this)->valueAt(Pos); + } +}; + +// Implementation of the static member field \c rosa::TokenizedStorage::Offsets. +template +const std::vector TokenizedStorage::Offsets = + TokenizedStorage::offsets(); + +} // End namespace rosa + +#endif // ROSA_SUPPORT_TOKENIZED_STORAGES_HPP diff --git a/include/rosa/support/type_numbers.hpp b/include/rosa/support/type_numbers.hpp index 2eec8f8..61d7ac9 100644 --- a/include/rosa/support/type_numbers.hpp +++ b/include/rosa/support/type_numbers.hpp @@ -1,228 +1,230 @@ //===-- rosa/support/type_numbers.hpp ---------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/type_numbers.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for registering supported types and representing them with /// numbers. /// /// \note This implementation is partially based on the \c type_number /// implementation of CAF. /// \todo Check license. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TYPE_NUMBERS_HPP #define ROSA_SUPPORT_TYPE_NUMBERS_HPP #include "rosa/support/atom.hpp" #include "rosa/support/math.hpp" #include "rosa/support/squashed_int.hpp" #include "rosa/support/type_helper.hpp" #include "rosa/support/types.hpp" #include #include namespace rosa { /// Compile-time list of all built-in types. /// \note Appending new types to the end of this list maintains backward /// compatibility in the sense that old builtin types have the same type number /// associated to them in both the old and new versions. But changing any of /// the already present types in the list breaks that backward compatibility. /// Should compatibility be broken, step \c rosa::TypeNumberVersion below! /// \note Keep this list in sync with the definition of /// \c rosa::NumberedTypeNames. +/// \note The built-in types are explicitly listed in the definition of +/// rosa::deluxe::DeluxeAgent. Keep those definitions in sync with this list. using BuiltinTypes = TypeList; /// Indicates the version number of \c rosa::BuiltinTypes. /// /// Software with the same version number are supposed to have backward /// compatible type numbering. /// /// \sa \c rosa::BultinTypes on backward compatibility. constexpr size_t TypeNumberVersion = 0; /// The number of built-in types. static constexpr size_t NumberOfBuiltinTypes = TypeListSize::Value; /// Anonymous namespace for helper facilities, consider it private. namespace { /// Tells if a type is not \c rosa::UnitType. /// /// \tparam T the type to check template struct IsNotUnitType { /// Denotes if \p T is the \c rosa::UnitType or not. static constexpr bool Value = !std::is_same::value; }; } // End namespace /// Integer type to store type numbers. /// \note The narrowest unsigned integer type that is wide enough to represent /// \c NumberOfBuiltinTypes different values. using type_nr_t = typename TypeListFind::Type, IsNotUnitType>::Type::Second; /// Turn \c rosa::type_nr_t into a strongly typed enumeration. /// /// Values of \c rosa::type_nr_t casted to \c rosa::TypeNumbers can be used in a /// type-safe way. enum class TypeNumber : type_nr_t {}; /// A type to cast type numbers into in order to output them to streams as /// numbers and not ASCII-codes. /// /// \note Use it for safety, necessary for printing \c uint8_t values. using printable_tn_t = printable_t; /// Casts a \c rosa::TypeNumber into \c rosa::printable_tn_t. /// /// \param TN \c rosa::TypeNumber to cast. #define PRINTABLE_TN(TN) static_cast(TN) /// Converts a \c rosa::TypeNumber into \c std::string. /// /// \param TN \c rosa::TypeNumber to convert /// /// \return \c std::string representing \p TN inline std::string to_string(const TypeNumber TN) { return std::to_string(static_cast(TN)); } /// \name TypeNumberOf /// \brief Computes \c rosa::TypeNumber for a type. /// /// The \c rosa::TypeNumber for a type \c T can be obtained as \code /// TypeNumberOf::Value /// \endcode /// /// \note \c rosa::TypeNumber for a type is based on the corresponding squashed /// type, except for \c bool and \c rosa::AtomConstant types. /// /// \sa \c rosa::SquashedType /// /// \note \c rosa::TypeNumber is the index of the type in \c rosa::BuiltinTypes /// starting from \c 1; index \c 0 indicates a non-builtin type. ///@{ /// Definition of the template for the general case. /// /// \tparam T type to get \c rosa::TypeNumber for template struct TypeNumberOf { static constexpr TypeNumber Value = static_cast( TypeListIndexOf>::Value + 1); }; /// Specialization for \c bool. template <> struct TypeNumberOf { static constexpr TypeNumber Value = static_cast(TypeListIndexOf::Value + 1); }; /// Specialization for \c rosa::AtomConstant. /// /// \note For a \c rosa::AtomConstant type, \c rosa::TypeNumber is based on the /// \c rosa::AtomValue wrapped into the actual \c rosa::AtomConstant. template struct TypeNumberOf> { static constexpr TypeNumber Value = TypeNumberOf::Value; }; ///@} // clang-format off /// List of type names for all builtin-types, indexed via \c rosa::TypeNumber. /// /// \note Keep this definition in sync with \c rosa::BuiltinTypes. constexpr std::array NumberedTypeNames {{ "atom", "i16", "i32", "i64", "i8", "ldouble", "str", "u16", "u32", "u64", "u8", "unit", "bool", "double", "float" }}; // clang-format on /// Tells if a \c rosa::TypeNumber is valid in the software. /// /// \note A \c rosa::TypeNumber generated by an incompatible version may be /// valid but may denote a type that is different from the \c rosa::TypeNumber /// denotes in the current software. That is why this validation needs to be /// done in connection to checking \c rosa::TypeNumberVersion as well. /// /// \param TN \c rosa::TypeNumber to validate in the context of the current /// software /// /// \return Whether \p TN is valid in the current software constexpr bool validTypeNumber(const TypeNumber TN) { // \todo Duplication of static_cast into a const variable would be // possible in C++14. return 0 < static_cast(TN) && static_cast(TN) <= NumberOfBuiltinTypes; } /// Provides information about the type corresponding to a \c rosa::TypeNumber. /// /// \tparam TN \c rosa::TypeNumber to get information for /// -/// \pre \p TN is a valid \c rosa::TypeNumber:\code +/// \pre Statically, \p TN is a valid \c rosa::TypeNumber:\code /// validTypeNumber(TN) /// \endcode template struct TypeForNumber { STATIC_ASSERT(validTypeNumber(TN), "not a valid type number"); /// \p TN as \c rosa::type_nr_t. static constexpr type_nr_t TNI = static_cast(TN); /// The builtin-type corresponding to \p TN. using Type = typename TypeListAt::Type; /// The size of \c Type. static constexpr size_t Size = sizeof(Type); /// Textual representation of the builtin-type. static constexpr const char *Name = NumberedTypeNames[TNI - 1]; }; } // End namespace rosa #endif // ROSA_SUPPORT_TYPE_NUMBERS_HPP diff --git a/include/rosa/support/type_token.hpp b/include/rosa/support/type_token.hpp index 6f30666..4d8ebca 100644 --- a/include/rosa/support/type_token.hpp +++ b/include/rosa/support/type_token.hpp @@ -1,284 +1,279 @@ //===-- rosa/support/type_token.hpp -----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/type_token.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for encoding TypeLists as unsigned integer values. /// /// \note **On the compatibility between different versions of the type token /// implementation:** /// Different software versions produce compatible type tokens as long as /// *backward compatibility* of \c rosa::BuiltinTypes is maintained (denoted by /// \c rosa::TypeNumberVersion) and the type token implementation uses the same /// type as \c rosa::token_t (boiling down to the same \c rosa::token::TokenBits /// value) and the same \c rosa::token::RepresentationBits value. Thus, /// interacting software need to cross-validate the aforementioned values to /// check compatibility. Interoperation between compatible sofware is limited /// to backward compatiblity, that is builtin types defined in both software /// versions are handled correctly but a newer system may produce a type token /// which is invalid in an old one. Therefore, tokens obtained from a compatible /// remote system need to be validated. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TYPE_TOKEN_HPP #define ROSA_SUPPORT_TYPE_TOKEN_HPP #include "rosa/support/type_numbers.hpp" namespace rosa { /// Integer type to store type tokens. /// /// \note The trade-off between the binary overhead of type encoding and the /// maximal size of encodable lists can be tuned by using unsigned integer types /// of different widths as \c rosa::token_t. using token_t = uint64_t; /// Sanity check in case someone would change \c rosa::token_t. STATIC_ASSERT(std::is_unsigned::value, "token_t is not an unsigned integer"); /// Turn \c rosa::token_t into a strongly typed enumeration. /// /// Values of \c rosa::token_t casted to \c rosa::Token can be used in a /// type-safe way. enum class Token : token_t {}; /// A type to cast tokens into in order to output them to streams as /// numbers and not ASCII-codes. /// /// \note Use it for safety, necessary for printing \c uint8_t values. using printable_token_t = printable_t; /// Casts a \c rosa::Token into \c rosa::printable_token_t. /// /// \param T \c rosa::Token to cast #define PRINTABLE_TOKEN(T) static_cast(T) /// Converts a \c rosa::Token into \c std::string. /// /// \param T \c rosa::Token to convert /// /// \return \c std::string representing \p T inline std::string to_string(const Token T) { return std::to_string(static_cast(T)); } /// Encloses constants related to the implementation of \c rosa::Token. namespace token { /// The number of bits in one \c rosa::Token. constexpr size_t TokenBits = sizeof(Token) * 8; /// The number of bits a builtin type can be uniquely encoded into, that is any /// valid \c rosa::TypeNumber can fit into. /// /// \note There is one extra bit position added for encoding so that providing a /// better chance to maintain backward comaptibility when \c rosa::BuiltinTypes /// is extended. constexpr size_t RepresentationBits = log2(NumberOfBuiltinTypes) + 1; /// Maximal size of uniquely tokenizable \c rosa::TypeList. constexpr size_t MaxTokenizableListSize = TokenBits / RepresentationBits; } // End namespace token /// \defgroup TypeListTokenImpl /// /// \brief Generates a \c rosa::Token for a squashed \c rosa::TypeList. /// /// \note Only to be used by the implementation of \c rosa::TypeListToken. ///@{ /// Declaration of the template. /// /// \tparam List \c rosa::TypeList to generate \c rosa::Token for template struct TypeListTokenImpl; /// Specialization for \c rosa::EmptyTypeList. template <> struct TypeListTokenImpl { static constexpr Token Value = static_cast(0); }; /// Specialization for a non-empty \c rosa::TypeList. template struct TypeListTokenImpl> { static constexpr TypeNumber TN = TypeNumberOf::Value; // Check if the generated type number is valid. STATIC_ASSERT(validTypeNumber(TN), "non-builtin type"); static constexpr Token Value = static_cast( (static_cast(TypeListTokenImpl>::Value) << token::RepresentationBits) | static_cast(TN)); }; ///@} /// \name TypeListToken /// /// \brief Generates a \c rosa::Token for a \c rosa::TypeList. /// /// \c rosa::Token for a \c rosa::TypeList \c List can be obtained as \code /// TypeListToken::Value /// \endcode /// /// \note The \c rosa::TypeList cannot have more than /// \c rosa::token::MaxTokenizableListSize elements and must be a subset of /// \c rosa::BuiltinTypes with respect to squashed integers. /// /// \note A generated \c rosa::Token uniquely represents a list of types, except /// for \c rosa::AtomConstant types. Observe that any \c rosa::AtomConstant is /// encoded as the type \c rosa::AtomValue. The type information on all separate /// \c rosa::AtomConstant types are lost and replaced by the \c rosa::AtomValue /// type whose actual value needs to be used in order to obtain the original /// \c rosa::AtomConstant type and so the full type information on the encoded /// \c rosa::TypeList. /// ///@{ /// Declaration of the template. /// /// \tparam List \c rosa::TypeList to generate \c rosa::Token for template struct TypeListToken; /// Implementation using \c rosa::TypeListTokenImpl. template struct TypeListToken> { /// \note \c rosa::TypeNumber is computed against \c rosa::squased_int_t for /// integral types, so let's do the same here. using List = typename SquashedTypeList>::Type; /// Check the length of the list here. /// \note Type validation is done one-by-one in \c rosa::TypeListTokenImpl. STATIC_ASSERT((TypeListSize::Value <= token::MaxTokenizableListSize), "too long list of types"); /// The \c rosa::Token for \p List. static constexpr Token Value = TypeListTokenImpl::Value; }; ///@} /// Convenience template to generate \c rosa::Token for a list of types. template using TypeToken = TypeListToken>; -/// Anonymous namespace with helper facilities, consider it private. -namespace { - -/// Extracts the \c rosa::TypeNumber of the first encoded type of a -/// \c rosa::Token. -/// -/// \note The returned type number is not validated. -/// -/// \param T \c rosa::Token to take the first \c rosa::TypeNumber from -/// -/// \return the first \c rosa::TypeNumber encoded in \p T -inline TypeNumber typeNumberOfHeadOfToken(const Token T) { - return static_cast(static_cast(T) & - ((1 << token::RepresentationBits) - 1)); -} - -} // End namespace - /// Tells if a given \c rosa::Token is valid. /// /// A \c rosa::Token is considered valid if it can be decoded by the current /// software. /// /// \note Validation gives a correct result only when \p T was generated by a /// compatible software. /// /// \sa Note for type_token.hpp on compatibility. /// /// \param T \c rosa::Token to validate /// /// \return if \p T is valid bool validToken(const Token T); /// Tells if a \c rosa::Token does encode an empty list of types. /// /// \param T \c rosa::Token to check /// /// \return if \p T encodes an empty list of types bool emptyToken(const Token T); /// Tells how many types are encoded in a \c rosa::Token. /// /// \param T \c rosa::Token to check /// /// \return how many types are encoded in \p T size_t lengthOfToken(const Token T); /// Tells the full memory size of the types encoded in a \c rosa::Token. /// /// The full memory size of the types encoded in a \c rosa::Token is the sum of /// the separate memory sizes of all the types encoded in the \c rosa::Token. /// /// \param T \c rosa::Token to check /// /// \return full memory size of the types encoded in \p T /// /// \pre \p T is valid:\code /// validToken(T) /// \endcode size_t sizeOfValuesOfToken(const Token T); +/// Extracts the \c rosa::TypeNumber of the first encoded type of a +/// \c rosa::Token. +/// +/// \note The returned type number is not validated. +/// +/// \param T \c rosa::Token to take the first \c rosa::TypeNumber from +/// +/// \return the first \c rosa::TypeNumber encoded in \p T +inline TypeNumber headOfToken(const Token T) { + return static_cast(static_cast(T) & + ((1 << token::RepresentationBits) - 1)); +} + /// Tells the memory size of the first type encoded in a \c rosa::Token. /// /// \param T \c rosa::Token to check the first encoded type of /// /// \return memory size of the first type encoded in \p T /// /// \pre \p T is not empty and valid:\code /// !empty(T) && validToken(T) /// \endcode size_t sizeOfHeadOfToken(const Token T); /// Gives the textual representation of the first type encoded in a /// \c rosa::Token. /// /// \param T \c rosa::Token to take the name of its first encoded type /// /// \return textual representation of the first type encoded in \p T /// /// \pre \p T is not empty and valid:\code /// !empty(T) && validToken(T) /// \endcode const char *nameOfHeadOfToken(const Token T); /// Updates a \c rosa::Token by dropping its first encoded type. /// /// \param [in,out] T \c rosa::Token to drop the first encoded type of void dropHeadOfToken(Token &T); /// Updates a \c rosa::Token by dropping a number of its first encoded types /// /// \param [in,out] T \c rosa::Token to drop the first \p N encoded types of /// \param N the number of types to drop from \p T void dropNOfToken(Token &T, const size_t N); /// Tells if the first encoded type of a \c rosa::Token is a given type. /// /// \tparam Type type to match the first encoded type of \p T against /// /// \param T \c rosa::Token whose first encoded type is to be matched against /// \p Type /// /// \return if the first encoded type of \p T is \p Type /// /// \pre \p T is not empty and valid:\code /// !empty(T) && validToken(T) /// \endcode template bool isHeadOfTokenTheSameType(const Token T) { ASSERT(!emptyToken(T) && validToken(T)); - return TypeNumberOf::Value == typeNumberOfHeadOfToken(T); + return TypeNumberOf::Value == headOfToken(T); } } // End namespace rosa #endif // ROSA_SUPPORT_TYPE_TOKEN_HPP diff --git a/include/rosa/support/types.hpp b/include/rosa/support/types.hpp index 994e5d8..3f6c7a2 100644 --- a/include/rosa/support/types.hpp +++ b/include/rosa/support/types.hpp @@ -1,523 +1,523 @@ //===-- rosa/support/types.hpp ----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/types.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Implementation of some basic convenience types. /// /// \note This implementation is partially based on the implementation of /// corresponding parts of CAF. /// \todo Check license. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TYPES_HPP #define ROSA_SUPPORT_TYPES_HPP #include "rosa/support/debug.hpp" #include namespace rosa { /* ************************************************************************** * * Unit * * ************************************************************************** */ /// A safe type to replace \c void. /// /// \c rosa::UnitType is analogous to \c void, but can be safely returned, /// stored, etc. to enable higher-order abstraction without cluttering code with /// exceptions for \c void (which can't be stored, for example). struct UnitType { /// Constructor, needs to do nothing. constexpr UnitType() noexcept {} /// Copy-constructor, needs to do nothing. constexpr UnitType(const UnitType &) noexcept {} }; /// Aliasing \c rosa::UnitType as \c rosa::unit_t. using unit_t = UnitType; /// The value of \c rosa::unit_t. /// /// \note Since a value of \c rosa::UnitType has no state, all instances of /// \c rosa::UnitType is equal and considered *the \c rosa::unit_t value*. static constexpr unit_t unit = unit_t{}; // NOLINT /// Returns the textual representation of any value of \c rosa::unit_t. /// /// \return textual representation of \c rosa::UnitType. inline std::string to_string(const unit_t &) { return "unit"; } /// \name LiftVoid /// \brief Lifts a type to avoid \c void. /// /// A type \c T can be lifted as \code /// typename LiftVoid::Type /// \endcode /// The resulted type is \c rosa::unit_t if \c T is \c void, and \c T itself /// otherwise. ///@{ /// Definition for the general case. /// /// \tparam T type to lift template struct LiftVoid { using Type = T; }; /// Specialization for \c void. template <> struct LiftVoid { using Type = unit_t; }; ///@} /// \name UnliftVoid /// \brief Unlifts a type already lifted by \c rosa::LiftVoid. /// /// A type \c T can be unlifted as \code /// typename UnliftVoid::Type /// \endcode /// The resulted type is \c void if \c T is \c rosa::unit_t -- that is \c void /// lifted by \c rosa::LiftVoid --, and \c T itself otherwise. /// ///@{ /// Definition for the general case. /// /// \tparam T type to unlift template struct UnliftVoid { using Type = T; }; /// Specialization for \c rosa::unit_t. template <> struct UnliftVoid { using Type = void; }; ///@} /* ************************************************************************** * * None * * ************************************************************************** */ /// Represents *nothing*. /// /// An instance of the type represents *nothing*, that can be used, e.g., for /// clearing an instance of \c rosa::Optional by assigning an instance of /// \c rosa::NoneType to it. struct NoneType { /// Constructor, needs to do nothing. constexpr NoneType(void) {} /// Evaluates the instance to \c bool. /// /// A "nothing" is always evaluates to \c false. constexpr explicit operator bool(void) const { return false; } }; /// Aliasing type \c rosa::NoneType as \c rosa::none_t. using none_t = NoneType; /// The value of \c rosa::none_t. /// /// \note Since a value of \c rosa::NoneType has no state, all instances of /// \c rosa::NoneType is equal and considered *the \c rosa::none_t value*. static constexpr none_t none = none_t{}; // NOLINT /// Returns the textual representation of any value of \c rosa::none_t. /// /// \return textual representation of \c rosa::NoneType. inline std::string to_string(const none_t &) { return "none"; } /* ************************************************************************** * * Optional * * ************************************************************************** */ /// \defgroup Optional /// \brief Represents an optional value. /// /// \note This implementation is compatible with \c std::optional of C++17. ///@{ /// Definition for the general case, optionally storing a value. /// /// \tparam T type of the optional value template class Optional { public: using Type = T; /// Creates an instance without value. /// /// \note Use it with its default parameter. Optional(const none_t & = none) : Valid(false) {} /// Creates a valid instance with value. /// /// \tparam U type of the \p X /// \tparam E always use it with default value! /// /// \param X value to store in the object /// /// \note The constructor is available for types that are convertible to \p T. template ::value>::type> Optional(U X) : Valid(false) { cr(std::move(X)); } /// Creates an instance as a copy of another one. /// /// \param Other the instance whose state to copy Optional(const Optional &Other) : Valid(false) { if (Other.Valid) { cr(Other.Value); } } /// Creates an instance by moving the state of another one. /// /// \param Other the instance whose state to obtain Optional(Optional &&Other) noexcept( std::is_nothrow_move_constructible::value) : Valid(false) { if (Other.Valid) { cr(std::move(Other.Value)); } } /// Destroys \p this object. ~Optional(void) { destroy(); } /// Updates \p this object by copying the state of another one. /// /// \param Other the instance whose state to copy /// /// \return reference of the updated instance Optional &operator=(const Optional &Other) { if (Valid) { if (Other.Valid) { Value = Other.Value; } else { destroy(); } } else if (Other.Valid) { cr(Other.Value); } return *this; } /// Updates \p this object by moving the state of another one. /// /// \param Other the instance whose state to obtain /// /// \return reference of the updated instance Optional &operator=(Optional &&Other) noexcept( std::is_nothrow_destructible::value &&std::is_nothrow_move_assignable::value) { if (Valid) { if (Other.Valid) { Value = std::move(Other.Value); } else { destroy(); } } else if (Other.Valid) { cr(std::move(Other.Value)); } return *this; } /// Checks whether \p this object contains a value. /// /// \return if \p this object contains a value explicit operator bool(void) const { return Valid; } /// Checks whether \p this object does not contain a value. /// /// \return if \p this object does not contain a value bool operator!(void)const { return !Valid; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value T &operator*(void) { ASSERT(Valid); return Value; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value const T &operator*(void)const { ASSERT(Valid); return Value; } /// Returns the value stored in \p this object. /// /// \return pointer to the stored value /// /// \pre \p this object contains a value const T *operator->(void)const { ASSERT(Valid); return &Value; } /// Returns the value stored in \p this object. /// /// \return pointer of the stored value /// /// \pre \p this object contains a value T *operator->(void) { ASSERT(Valid); return &Value; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value T &value(void) { ASSERT(Valid); return Value; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value const T &value(void) const { ASSERT(Valid); return Value; } /// Returns the stored value or a default. /// /// If \p this object contains a value, then the stored value is returned. A /// given default value is returned otherwise. /// /// \param DefaultValue the value to return if \p this object does not contain /// a value /// /// \return reference to either the stored value or \p DefaultValue if \p this /// object does not contain a value const T &valueOr(const T &DefaultValue) const { - return Valid ? Value() : DefaultValue; + return Valid ? Value : DefaultValue; } private: /// Deallocates the stored value if any. void destroy(void) { if (Valid) { Value.~T(); Valid = false; } } /// Updates the state of \p this object by moving a value into it. /// /// \tparam V type of \p X /// - /// \param X value to move into + /// \param X value to move /// /// \pre \p this object does not contain a value template void cr(V &&X) { ASSERT(!Valid); Valid = true; new (&Value) T(std::forward(X)); } /// Denotes if \p this object contains a value. bool Valid; /// Holds the stored value if any. union { T Value; ///< The stored value. }; }; /// Specialization storing a reference. /// /// The specialization allows \p rosa::Optional to hold a reference /// rather than an actual value with minimal overhead. /// /// \tparam T the base type whose reference is to be stored template class Optional { public: using Type = T; /// Creates an instance without reference /// /// \note Use it with its default parameter. Optional(const none_t & = none) : Value(nullptr) {} /// Creates a valid instance with reference. /// /// \param X reference to store in the object Optional(T &X) : Value(&X) {} /// Creates a valid instance with reference. /// /// \param X pointer to store in the object as reference Optional(T *X) : Value(X) {} /// Creates an instance as a copy of another one. /// /// \param Other the instance whose state to copy Optional(const Optional &Other) = default; /// Updates \p this object by copying the state of another one. /// /// \param Other the instance whose state to copy /// /// \return reference of the updated instance Optional &operator=(const Optional &Other) = default; /// Checks whether \p this object contains a reference. /// /// \return if \p this object contains a reference explicit operator bool(void) const { return Value != nullptr; } /// Checks whether \p this object does not contain a reference. /// /// \return if \p this object does not contain a reference bool operator!(void)const { return !Value; } /// Returns the reference stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference T &operator*(void) { ASSERT(Value); return *Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference const T &operator*(void)const { ASSERT(Value); return *Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference T *operator->(void) { ASSERT(Value); return Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference const T *operator->(void)const { ASSERT(Value); return Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference T &value(void) { ASSERT(Value); return *Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference const T &value(void) const { ASSERT(Value); return *Value; } /// Returns the stored reference or a default. /// /// If \p this object contains a reference, then the stored reference is /// returned. A given default value is returned otherwise. /// /// \param DefaultValue the value to return if \p this object does not contain /// a reference /// /// \return either the stored reference or \p DefaultValue if \p this object /// does not contain a reference const T &valueOr(const T &DefaultValue) const { - return Value ? Value() : DefaultValue; + return Value ? Value : DefaultValue; } private: /// The stored reference as a pointer. T *Value; }; /// Specialization storing \c void. /// /// The specialization allows \c rosa::Optional to implement a flag for \c void. template <> class Optional { public: using Type = unit_t; /// Creates an instance with a \c false flag. /// /// \note Use it with its default parameter. Optional(none_t = none) : Value(false) {} /// Creates an instance with a \c true flag. /// /// \note The only argument is ignored because it can be *the \c rosa::unit_t /// value* only. Optional(unit_t) : Value(true) {} /// Creates an instance as a copy of another one. /// /// \param Other the instance whose state to copy Optional(const Optional &Other) = default; /// Updates \p this object by copying the state of another one. /// /// \param Other the instance whose state to copy /// /// \return reference of the updated instance Optional &operator=(const Optional &Other) = default; /// Checks whether \p this object contains a \p true flag. /// /// \return if \p this object contains a \p true flag. explicit operator bool(void) const { return Value; } /// Checks whether \p this object contains a \p false flag. /// /// \return if \p this object contains a \p false flag. bool operator!(void)const { return !Value; } private: /// The stored flag. bool Value; }; ///@} } // End namespace rosa #endif // ROSA_SUPPORT_TYPES_HPP diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6a6246c..25754a4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,10 +1,6 @@ # Add the different subdirectories. add_subdirectory(config) add_subdirectory(support) add_subdirectory(core) add_subdirectory(agent) - -# Refactor the content into a proper structure -# and remove this eventually: -add_subdirectory(gen_agent_test2) - +add_subdirectory(deluxe) diff --git a/lib/core/AgentHandle.cpp b/lib/core/AgentHandle.cpp index b7e1f63..5f3fda9 100644 --- a/lib/core/AgentHandle.cpp +++ b/lib/core/AgentHandle.cpp @@ -1,50 +1,50 @@ //===-- core/AgentHandle.cpp ------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file core/AgentHandle.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Implementation of rosa/core/AgentHandle.hpp. /// //===----------------------------------------------------------------------===// #include "rosa/core/AgentHandle.hpp" #include "rosa/core/Agent.hpp" namespace rosa { -AgentHandle::AgentHandle(Agent &A, bool) : A(A), S(A.system()) {} +AgentHandle::AgentHandle(Agent &A, bool) noexcept : A(A), S(A.system()) {} AgentHandle::AgentHandle(Agent &A) : A(A), S(A.system()) { ASSERT(S.isUnitRegistered(A)); } AgentHandle::operator bool(void) const noexcept { // \note The referred \c rosa::MessageSystem is supposed to be still alive. return S.isUnitRegistered(A); } bool AgentHandle::operator==(const AgentHandle &H) const noexcept { // Return if the referred \c rosa::Agent is the same object in both // \c rosa::AgentHandler instances. return &A == &H.A; } AgentHandle AgentHandle::self(void) noexcept { // Return a copy of \p this object. return *this; } void AgentHandle::sendMessage(message_t &&M) noexcept { ASSERT(bool(*this)); S.send(*this, std::move(M)); } } // End namespace rosa diff --git a/lib/core/MessagingSystem.cpp b/lib/core/MessagingSystem.cpp index 4358dd2..30d5879 100644 --- a/lib/core/MessagingSystem.cpp +++ b/lib/core/MessagingSystem.cpp @@ -1,28 +1,34 @@ //===-- core/MessagingSystem.cpp --------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file core/MessagingSystem.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Implementation of rosa/core/MessagingSystem.hpp. /// //===----------------------------------------------------------------------===// #include "rosa/core/MessagingSystem.hpp" +#include "rosa/core/Agent.hpp" + #include "MessagingSystemImpl.hpp" namespace rosa { std::unique_ptr MessagingSystem::createSystem(const std::string &Name) noexcept { return std::unique_ptr(new MessagingSystemImpl(Name)); } +void MessagingSystem::destroyAgent(const AgentHandle &H) noexcept { + destroyUnit(unwrapAgent(H)); +} + } // End namespace rosa diff --git a/lib/core/MessagingSystemImpl.hpp b/lib/core/MessagingSystemImpl.hpp index 2370837..b8d4cb4 100644 --- a/lib/core/MessagingSystemImpl.hpp +++ b/lib/core/MessagingSystemImpl.hpp @@ -1,103 +1,105 @@ //===-- core/MessagingSystemImpl.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file core/MessagingSystemImpl.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of a basic implementation of the \c rosa::MessagingSystem /// interface. /// //===----------------------------------------------------------------------===// #ifndef ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP #define ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP #include "SystemImpl.hpp" #include "rosa/core/MessagingSystem.hpp" namespace rosa { /// Implements \c rosa::MessagingSystem by extending \c rosa::SystemImpl with /// adding a simple implementation of sending messages: directly invoking /// \c rosa::Agent instances with given \c rosa::Message objects. /// /// \note Keep in mind that sending a \c rosa::Message object with this /// implementation translates into a direct function call. class MessagingSystemImpl : public MessagingSystem, public SystemImpl { /// Alies for the base-class \c rosa::SystemImpl. using Base = SystemImpl; public: /// Creates an instance. /// /// \param Name name of the new instance MessagingSystemImpl(const std::string &Name) noexcept; protected: - /// \defgroup \c rosa::MessagingSystemImpl call forwardings + /// \defgroup MessagingSystemImplCallForwarding + /// + /// \c rosa::MessagingSystemImpl call forwardings /// /// \note Simply forwarding calls to implementations provided by /// \c rosa::MessagingSystem::Base for the \c rosa::System interface. /// /// \todo How could we use the inherited implementations in a simpler way? ///@{ id_t nextId(void) noexcept override { return Base::nextId(); } bool isSystemCleaned(void) const noexcept override { return Base::isSystemCleaned(); } void markCleaned(void) noexcept override { Base::markCleaned(); } void registerUnit(Unit &U) noexcept override { Base::registerUnit(U); } void destroyUnit(Unit &U) noexcept override { Base::destroyUnit(U); } bool isUnitRegistered(const Unit &U) const noexcept override { return Base::isUnitRegistered(U); } public: const std::string &name(void) const noexcept override { return Base::name(); } size_t numberOfConstructedUnits(void) const noexcept override { return Base::numberOfConstructedUnits(); } size_t numberOfLiveUnits(void) const noexcept override { return Base::numberOfLiveUnits(); } bool empty(void) const noexcept override { return Base::empty(); } ///@} /// Sends a \c rosa::message_t instance to the \c rosa::Agent instance /// referred by a \c rosa::AgentHandle -- by directly invoking the /// \c rosa::Agent instance with the \c rosa::Message object. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \param H refers to the \c rosa::Agent instance to send to /// \param M message to send /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode void send(const AgentHandle &H, message_t &&M) noexcept override; }; } // End namespace rosa #endif // ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP diff --git a/lib/deluxe/CMakeLists.txt b/lib/deluxe/CMakeLists.txt new file mode 100755 index 0000000..41a22b3 --- /dev/null +++ b/lib/deluxe/CMakeLists.txt @@ -0,0 +1,20 @@ +set(LIB_INCLUDE_DIR ${ROSA_MAIN_INCLUDE_DIR}/rosa/deluxe) + +add_library(ROSADeluxe + ${LIB_INCLUDE_DIR}/namespace.h + namespace.cpp + ${LIB_INCLUDE_DIR}/DeluxeAtoms.hpp + DeluxeAtoms.cpp + ${LIB_INCLUDE_DIR}/DeluxeSensor.hpp + DeluxeSensor.cpp + ${LIB_INCLUDE_DIR}/DeluxeAgent.hpp + DeluxeAgent.cpp + ${LIB_INCLUDE_DIR}/DeluxeSystem.hpp + DeluxeSystem.cpp + DeluxeSystemImpl.hpp + DeluxeSystemImpl.cpp + ${LIB_INCLUDE_DIR}/DeluxeContext.hpp + DeluxeContext.cpp + ) + +ROSA_add_library_dependencies(ROSADeluxe ROSACore) diff --git a/lib/deluxe/DeluxeAgent.cpp b/lib/deluxe/DeluxeAgent.cpp new file mode 100755 index 0000000..48ae72f --- /dev/null +++ b/lib/deluxe/DeluxeAgent.cpp @@ -0,0 +1,157 @@ +//===-- deluxe/DeluxeAgent.cpp ----------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeAgent.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation of rosa/deluxe/DeluxeAgent.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/deluxe/DeluxeAgent.hpp" +#include "rosa/deluxe/DeluxeSensor.hpp" + +#include + +namespace rosa { +namespace deluxe { + +bool DeluxeAgent::inv(void) const noexcept { + // Check container sizes. + if (!(InputTypes.size() == NumberOfInputs && + InputChanged.size() == NumberOfInputs && + InputValues->size() == NumberOfInputs && + Slaves.size() == NumberOfInputs)) + return false; + + // Check *slave* types and validate *slave* registrations and reverse lookup + // information. + std::map RefIds; // Build up a reference of SlaveIds in this. + for (size_t I = 0; I < NumberOfInputs; ++I) { + // First, validate input types at position \c I. + const TypeNumber T = InputTypes[I]; + + if (InputValues->typeAt(I) != T) + return false; + + // Check the registered *slave* at position \c I. + const auto &S = Slaves[I]; + // If \c S is empty, nothing to check. + if (!S) + continue; + + // \c S is not empty here. + // Check the `OutputType` of the registered *slave*. + const auto &A = unwrapAgent(*S); + if (!((A.Kind == atoms::SensorKind && + static_cast(A).OutputType == T) || + (A.Kind == atoms::AgentKind && + static_cast(A).OutputType == T))) + return false; + + // Validate that the *slave* is not registered more than once. + if (std::any_of( + Slaves.begin() + I, Slaves.end(), + [&S](const Optional &O) { return O && *S == *O; })) + return false; + + // Build the content of \c RefIds. + RefIds.emplace(A.Id, I); + } + + // Validate *slave* reverse lookup information against our reference. + if (RefIds != SlaveIds) + return false; + + // All checks were successful, the invariant is held. + return true; +} + +DeluxeAgent::~DeluxeAgent(void) noexcept { + ASSERT(inv()); + LOG_TRACE("Destroying DeluxeAgent..."); +} + +Optional DeluxeAgent::master(void) const noexcept { + ASSERT(inv()); + return Master; +} + +void DeluxeAgent::registerMaster(const Optional Master) noexcept { + ASSERT(inv() && (!Master || unwrapAgent(*Master).Kind == atoms::AgentKind)); + + this->Master = Master; + + ASSERT(inv()); +} + +TypeNumber DeluxeAgent::inputType(const size_t Pos) const noexcept { + ASSERT(inv() && Pos < NumberOfInputs); + return InputTypes[Pos]; +} + +Optional DeluxeAgent::slave(const size_t Pos) const noexcept { + ASSERT(inv() && Pos < NumberOfInputs); + return Slaves[Pos]; +} + +void DeluxeAgent::registerSlave(const size_t Pos, + const Optional Slave) noexcept { + ASSERT(inv() && Pos < NumberOfInputs && + (!Slave || + (unwrapAgent(*Slave).Kind == atoms::SensorKind && + static_cast(unwrapAgent(*Slave)).OutputType == + InputTypes[Pos]) || + (unwrapAgent(*Slave).Kind == atoms::AgentKind && + static_cast(unwrapAgent(*Slave)).OutputType == + InputTypes[Pos]))); + + // If registering an actual *slave*, not just clearing the slot, make sure + // the same *slave* is not registered to another slot. + if (Slave) { + auto It = SlaveIds.find(unwrapAgent(*Slave).Id); + if (It != SlaveIds.end()) { + Slaves[It->second] = {};//Optional(); + SlaveIds.erase(It); + } + } + + // Obtain the place whose content is to be replaced with \p Slave + auto &S = Slaves[Pos]; + + // If there is already a *slave* registered at \p Pos, clear reverse lookup + // information for it. + if (S) { + ASSERT(SlaveIds.find(unwrapAgent(*S).Id) != + SlaveIds.end()); // Sanity check. + SlaveIds.erase(unwrapAgent(*S).Id); + } + + // Register \p Slave at \p Pos. + S = Slave; + + // If registering an actual *slave*, not just clearing the slot, register + // reverse lookup information for the new *slave*. + if (Slave) { + SlaveIds.emplace(unwrapAgent(*Slave).Id, Pos); + } + + ASSERT(inv()); +} + +void DeluxeAgent::handleTrigger(atoms::Trigger) noexcept { + ASSERT(inv()); + + FP(); + + ASSERT(inv()); +} + +} // End namespace deluxe +} // End namespace rosa diff --git a/lib/deluxe/DeluxeAtoms.cpp b/lib/deluxe/DeluxeAtoms.cpp new file mode 100755 index 0000000..33c0430 --- /dev/null +++ b/lib/deluxe/DeluxeAtoms.cpp @@ -0,0 +1,20 @@ +//===-- deluxe/DeluxeAtoms.cpp ----------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeAtoms.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation of deluxe/DeluxeAtoms.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/deluxe/DeluxeAtoms.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/deluxe/DeluxeAtoms.hpp" diff --git a/lib/deluxe/DeluxeContext.cpp b/lib/deluxe/DeluxeContext.cpp new file mode 100755 index 0000000..cf3e0fe --- /dev/null +++ b/lib/deluxe/DeluxeContext.cpp @@ -0,0 +1,151 @@ +//===-- deluxe/DeluxeContext.cpp --------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeContext.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation for rosa/deluxe/DeluxeContext.hpp. +/// +//===----------------------------------------------------------------------===// + +#define ROSA_LIB_DELUXE_DELUXECONTEXT_CPP // For including helper macros. + +#include "rosa/deluxe/DeluxeContext.hpp" + +#include + +namespace rosa { +namespace deluxe { + +std::unique_ptr +DeluxeContext::create(const std::string &Name) noexcept { + return std::unique_ptr(new DeluxeContext(Name)); +} + +DeluxeContext::DeluxeContext(const std::string &Name) noexcept + : System(DeluxeSystem::createSystem(Name)) { + LOG_TRACE("DeluxeContext for " + System->name() + " is created."); +} + +DeluxeContext::~DeluxeContext(void) noexcept { + // \c rosa::deluxe::DeluxeContext::System is not used outside, just clean it. + for(auto U : DeluxeUnits) { + System->destroyAgent(U); + } + System->markCleaned(); + LOG_TRACE("DeluxeContext for " + System->name() + + " prepared for destruction."); +} + +DeluxeContext::ErrorCode +DeluxeContext::connectSensor(AgentHandle &Agent, const size_t Pos, + AgentHandle &Sensor, + const std::string &Description) noexcept { + // Generate trace log. + auto &Trace = LOG_TRACE_STREAM; + Trace << "Establishing connection"; + if (!Description.empty()) { + Trace << " '" << Description << "'"; + } + Trace << " between " << System->unwrapAgent(Sensor).FullName << " and " + << System->unwrapAgent(Agent).FullName << "\n"; + + // Make sure preconditions are met. + if (!System->isDeluxeAgent(Agent)) { + DCRETERROR(ErrorCode::NotAgent); + } else if (!System->isDeluxeSensor(Sensor)) { + DCRETERROR(ErrorCode::NotSensor); + } + auto A = System->getDeluxeAgent(Agent); + auto S = System->getDeluxeSensor(Sensor); + ASSERT(A && S); // Sanity check. + if (Pos >= A->NumberOfInputs) { + DCRETERROR(ErrorCode::WrongPosition); + } else if (A->inputType(Pos) != S->OutputType) { + DCRETERROR(ErrorCode::TypeMismatch); + } else if (A->slave(Pos)) { + DCRETERROR(ErrorCode::AlreadyHasSlave); + } else if (S->master()) { + DCRETERROR(ErrorCode::AlreadyHasMaster); + } + + // Do register. + A->registerSlave(Pos, {Sensor}); + S->registerMaster({Agent}); + + return ErrorCode::NoError; +} + +DeluxeContext::ErrorCode +DeluxeContext::connectAgents(AgentHandle &Master, const size_t Pos, + AgentHandle &Slave, + const std::string &Description) noexcept { + // Generate trace log. + auto &Trace = LOG_TRACE_STREAM; + Trace << "Establishing connection"; + if (!Description.empty()) { + Trace << " '" << Description << "'"; + } + Trace << " between " << System->unwrapAgent(Slave).FullName << " and " + << System->unwrapAgent(Master).FullName << "\n"; + + // Make sure preconditions are met. + if (!(System->isDeluxeAgent(Master) && System->isDeluxeAgent(Slave))) { + DCRETERROR(ErrorCode::NotAgent); + } + auto M = System->getDeluxeAgent(Master); + auto S = System->getDeluxeSensor(Slave); + ASSERT(M && S); // Sanity check. + if (Pos >= M->NumberOfInputs) { + DCRETERROR(ErrorCode::WrongPosition); + } else if (M->inputType(Pos) != S->OutputType) { + DCRETERROR(ErrorCode::TypeMismatch); + } else if (M->slave(Pos)) { + DCRETERROR(ErrorCode::AlreadyHasSlave); + } else if (S->master()) { + DCRETERROR(ErrorCode::AlreadyHasMaster); + } + + // Do register. + M->registerSlave(Pos, {Slave}); + S->registerMaster({Master}); + + return ErrorCode::NoError; +} + +std::weak_ptr DeluxeContext::getSystem(void) const noexcept { + return std::weak_ptr(System); +} + +void DeluxeContext::initializeSimulation(void) noexcept { + // Clear simulation data sources from sensors. + for (auto U : DeluxeUnits) { + if (auto S = System->getDeluxeSensor(U)) { + S->clearSimulationDataSource(); + } + } +} + +void DeluxeContext::simulate(const size_t NumCycles) const noexcept { + ASSERT(std::all_of( + DeluxeUnits.begin(), DeluxeUnits.end(), [&](const AgentHandle &H) { + return System->isDeluxeAgent(H) || + System->isDeluxeSensor(H) && + System->getDeluxeSensor(H)->simulationDataSourceIsSet(); + })); + for (size_t I = 1; I <= NumCycles; ++I) { + LOG_TRACE("Simulation cycle: " + std::to_string(I)); + for (auto U : DeluxeUnits) { + U.sendMessage(Message::create(atoms::Trigger::Value)); + } + } +} + +} // End namespace deluxe +} // End namespace rosa diff --git a/lib/deluxe/DeluxeSensor.cpp b/lib/deluxe/DeluxeSensor.cpp new file mode 100755 index 0000000..31172ec --- /dev/null +++ b/lib/deluxe/DeluxeSensor.cpp @@ -0,0 +1,52 @@ +//===-- deluxe/DeluxeSensor.cpp ---------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeSensor.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation of rosa/deluxe/DeluxeSensor.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/deluxe/DeluxeSensor.hpp" + +namespace rosa { +namespace deluxe { + +DeluxeSensor::~DeluxeSensor(void) noexcept { + LOG_TRACE("Destroying DeluxeSensor..."); +} + +Optional DeluxeSensor::master(void) const noexcept { + return Master; +} + +void DeluxeSensor::registerMaster(const Optional Master) noexcept { + ASSERT(!Master || unwrapAgent(*Master).Kind == atoms::AgentKind); + + this->Master = Master; +} + +void DeluxeSensor::clearSimulationDataSource(void) noexcept { + SFP = nullptr; +} + +bool DeluxeSensor::simulationDataSourceIsSet(void) const noexcept { + return SFP != nullptr; +} + +void DeluxeSensor::handleTrigger(atoms::Trigger) noexcept { + // Use \c rosa::deluxe::DeluxeSensor::SFP if set, otherwise + // \c rosa::deluxe::DeluxeSensor::FP. + const H &F = SFP ? SFP : FP; + F(); +} + +} // End namespace deluxe +} // End namespace rosa diff --git a/lib/deluxe/DeluxeSystem.cpp b/lib/deluxe/DeluxeSystem.cpp new file mode 100755 index 0000000..be0cd97 --- /dev/null +++ b/lib/deluxe/DeluxeSystem.cpp @@ -0,0 +1,66 @@ +//===-- deluxe/DeluxeSystem.cpp ---------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeSystem.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation of rosa/deluxe/DeluxeSystem.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/deluxe/DeluxeSystem.hpp" + +#include "DeluxeSystemImpl.hpp" + +namespace rosa { +namespace deluxe { + +std::unique_ptr +DeluxeSystem::createSystem(const std::string &Name) noexcept { + return std::unique_ptr(new DeluxeSystemImpl(Name)); +} + +Optional +DeluxeSystem::getDeluxeSensor(const AgentHandle &H) const noexcept { + if (isDeluxeSensor(H)) { + return {static_cast(unwrapAgent(H))}; + } else { + return {}; + } +} + +Optional DeluxeSystem::getDeluxeSensor(AgentHandle &H) const + noexcept { + if (isDeluxeSensor(H)) { + return {static_cast(unwrapAgent(H))}; + } else { + return {}; + } +} + +Optional +DeluxeSystem::getDeluxeAgent(const AgentHandle &H) const noexcept { + if (isDeluxeAgent(H)) { + return {static_cast(unwrapAgent(H))}; + } else { + return {}; + } +} + +Optional DeluxeSystem::getDeluxeAgent(AgentHandle &H) const + noexcept { + if (isDeluxeAgent(H)) { + return {static_cast(unwrapAgent(H))}; + } else { + return {}; + } +} + +} // End namespace deluxe +} // End namespace rosa diff --git a/lib/deluxe/DeluxeSystemImpl.cpp b/lib/deluxe/DeluxeSystemImpl.cpp new file mode 100755 index 0000000..e5d0220 --- /dev/null +++ b/lib/deluxe/DeluxeSystemImpl.cpp @@ -0,0 +1,37 @@ +//===-- deluxe/DeluxeSystemImpl.cpp -----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeSystemImpl.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation of deluxe/DeluxeSystemImpl.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "DeluxeSystemImpl.hpp" + +namespace rosa { +namespace deluxe { + +DeluxeSystemImpl::DeluxeSystemImpl(const std::string &Name) noexcept + : DeluxeSystem(), + MessagingSystemImpl(Name) { + LOG_TRACE("System '" + Name + "' also has a deluxe flavor"); +} + +bool DeluxeSystemImpl::isDeluxeSensor(const AgentHandle &H) const noexcept { + return unwrapAgent(H).Kind == atoms::SensorKind; +} + +bool DeluxeSystemImpl::isDeluxeAgent(const AgentHandle &H) const noexcept { + return unwrapAgent(H).Kind == atoms::AgentKind; +} + +} // End namespace deluxe +} // End namespace rosa diff --git a/lib/deluxe/DeluxeSystemImpl.hpp b/lib/deluxe/DeluxeSystemImpl.hpp new file mode 100755 index 0000000..9e50354 --- /dev/null +++ b/lib/deluxe/DeluxeSystemImpl.hpp @@ -0,0 +1,112 @@ +//===-- deluxe/DeluxeSystemImpl.hpp -----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/DeluxeSystemImpl.hpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Declaration of a basic implementation of the +/// \c rosa::deluxe::DeluxeSystem interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_LIB_DELUXE_DELUXESYSTEMIMPL_HPP +#define ROSA_LIB_DELUXE_DELUXESYSTEMIMPL_HPP + +#include "../core/MessagingSystemImpl.hpp" + +#include "rosa/deluxe/DeluxeSystem.hpp" + +namespace rosa { +namespace deluxe { + +/// Implements \c rosa::deluxe::DeluxeSystem by extending +/// \c rosa::MessagingSystemImpl. +class DeluxeSystemImpl : public DeluxeSystem, public MessagingSystemImpl { + /// Alies for the base-class \c rosa::MessagingSystemImpl. + using Base = MessagingSystemImpl; + +public: + /// Creates an instance. + /// + /// \param Name name of the new instance + DeluxeSystemImpl(const std::string &Name) noexcept; + + /// + ~DeluxeSystemImpl(void) noexcept; +protected: + /// \defgroup DeluxeSystemImplCallForwardings + /// + /// \c rosa::deluxe::DeluxeSystemImpl call forwardings + /// + /// \note Simply forwarding calls to implementations provided by + /// \c rosa::deluxe::DeluxeSystem::Base for the \c rosa::MessagingSystem + /// interface. + /// + /// \todo How could we use the inherited implementations in a simpler way? + ///@{ + + id_t nextId(void) noexcept override { return Base::nextId(); } + + bool isSystemCleaned(void) const noexcept override { + return Base::isSystemCleaned(); + } + + void markCleaned(void) noexcept override { Base::markCleaned(); } + + void registerUnit(Unit &U) noexcept override { Base::registerUnit(U); } + + void destroyUnit(Unit &U) noexcept override { Base::destroyUnit(U); } + + bool isUnitRegistered(const Unit &U) const noexcept override { + return Base::isUnitRegistered(U); + } + +public: + const std::string &name(void) const noexcept override { return Base::name(); } + + size_t numberOfConstructedUnits(void) const noexcept override { + return Base::numberOfConstructedUnits(); + } + + size_t numberOfLiveUnits(void) const noexcept override { + return Base::numberOfLiveUnits(); + } + + bool empty(void) const noexcept override { return Base::empty(); } + + void send(const AgentHandle &H, message_t &&M) noexcept override { + Base::send(H, std::move(M)); + } + + ///@} + + /// Tells whether a \c rosa::AgentHandle refers to a + /// \c rosa::deluxe::DeluxeSensor owned by \p this object. + /// + /// \param H \c rosa::AgentHandle to check + /// + /// \return whether \p H refers to a \c rosa::deluxe::DeluxeSensor owned by + /// \p this object + bool isDeluxeSensor(const AgentHandle &H) const noexcept override; + + /// Tells whether a \c rosa::AgentHandle refers to a + /// \c rosa::deluxe::DeluxeAgent owned by \p this object. + /// + /// \param H \c rosa::AgentHandle to check + /// + /// \return whether \p H refers to a \c rosa::deluxe::DeluxeAgent owned by + /// \p this object + bool isDeluxeAgent(const AgentHandle &H) const noexcept override; + +}; + +} // End namespace deluxe +} // End namespace rosa + +#endif // ROSA_LIB_DELUXE_DELUXESYSTEMIMPL_HPP diff --git a/lib/deluxe/namespace.cpp b/lib/deluxe/namespace.cpp new file mode 100755 index 0000000..d565236 --- /dev/null +++ b/lib/deluxe/namespace.cpp @@ -0,0 +1,20 @@ +//===-- deluxe/namespace.cpp ------------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file deluxe/namespace.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation for rosa/deluxe/namespace.h. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/deluxe/namespace.h. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/deluxe/namespace.h" diff --git a/lib/gen_agent_test2/Agent.cpp b/lib/gen_agent_test2/Agent.cpp deleted file mode 100644 index 8bf7604..0000000 --- a/lib/gen_agent_test2/Agent.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "Agent.h" -#include "printError.h" -#include - -// TODO: Move this include to ControlModule -#include "instruction_set_architecture.h" - -#define PRINT_READING - -void Agent::init_agent() { - sensorHandlerOfAgent = NULL; - slaveAgentHandlerOfAgent = NULL; - masterAgentHandlerOfAgent = NULL; -} - -Agent::Agent() { - set_name(NO_NAME); - init_agent(); -} - -Agent::Agent(const char *name) { - set_name(name); - init_agent(); -} - -bool Agent::set_sensorHandlerOfAgent() { - sensorHandlerOfAgent = new SensorHandlerOfAgent(); - - if (sensorHandlerOfAgent == NULL) { - printError("Couldn't create Sensor Handler!"); - return false; - } - return true; -} - -bool Agent::del_sensorHandlerOfAgent() { - if (sensorHandlerOfAgent != NULL) { - // TODO: Unmount/delete all sensorSlots with everything inside (history - // module, confidence module, ...) - delete sensorHandlerOfAgent; - return true; - } - return false; -} - -SensorHandlerOfAgent *Agent::get_sensorHandlerOfAgent() { - if (sensorHandlerOfAgent == NULL) { - set_sensorHandlerOfAgent(); - } - return sensorHandlerOfAgent; -} - -bool Agent::set_slaveAgentHandlerOfAgent() { - slaveAgentHandlerOfAgent = new SlaveAgentHandlerOfAgent(); - - if (slaveAgentHandlerOfAgent == NULL) { - printError("Couldn't create Slave Agent Handler!"); - return false; - } - return true; -} - -bool Agent::del_slaveAgentHandlerOfAgent() { - if (slaveAgentHandlerOfAgent != NULL) { - // TODO: Unmount/delete all SlaveAgentSlots with everything inside (history - // module, confidence module, ...) - delete slaveAgentHandlerOfAgent; - return true; - } - return false; -} - -SlaveAgentHandlerOfAgent *Agent::get_slaveAgentHandlerOfAgent() { - if (slaveAgentHandlerOfAgent == NULL) { - set_slaveAgentHandlerOfAgent(); - } - return slaveAgentHandlerOfAgent; -} - -bool Agent::set_masterAgentHandlerOfAgent() { - masterAgentHandlerOfAgent = new MasterAgentHandlerOfAgent(); - - if (masterAgentHandlerOfAgent == NULL) { - printError("Couldn't create Master Agent Handler!"); - return false; - } - return true; -} - -bool Agent::del_masterAgentHandlerOfAgent() { - if (masterAgentHandlerOfAgent != NULL) { - // TODO: Unmount/delete (all) MasterAgentSlot(s) with everything inside - delete masterAgentHandlerOfAgent; - return true; - } - return false; -} - -MasterAgentHandlerOfAgent *Agent::get_masterAgentHandlerOfAgent() { - if (masterAgentHandlerOfAgent == NULL) { - set_masterAgentHandlerOfAgent(); - } - return masterAgentHandlerOfAgent; -} - -void Agent::trigger() { - - // TODO: make control_module to set the method of operating for each agent - // individual - - // Job: Read all sensory data - if (sensorHandlerOfAgent != NULL) { - printf("%s->sensorHandler: ", name); - sensorHandlerOfAgent->read_allSensorValues(); - } - - // Job: Read all slave agent data - if (slaveAgentHandlerOfAgent != NULL) { - printf("%s->slaveAgentHandler: ", name); - slaveAgentHandlerOfAgent->read_allSlaveAgentValues(); - } - - // Job: Just pass the Sensory Data (without abstraction) to master - if (masterAgentHandlerOfAgent != NULL) { - if (sensorHandlerOfAgent != NULL) { - vector *vSensoryData = - sensorHandlerOfAgent->get_vMountedSensors(); - for (auto &sensorSlot : *vSensoryData) { - // TODO: also for int - float sensorValue; - if (sensorSlot->get_sensorValue(&sensorValue)) { - masterAgentHandlerOfAgent->pass_msgToSendBuffer(ISA_SensoryData); - masterAgentHandlerOfAgent->pass_msgToSendBuffer(sensorValue); - } - } - } - masterAgentHandlerOfAgent->send_msgs(); - } -} - diff --git a/lib/gen_agent_test2/Agent.h b/lib/gen_agent_test2/Agent.h deleted file mode 100644 index bb66723..0000000 --- a/lib/gen_agent_test2/Agent.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef AGENT_HEADERFILE -#define AGENT_HEADERFILE - -#include "MasterAgentHandlerOfAgent.h" -#include "Node.h" -#include "SensorHandlerOfAgent.h" -#include "SlaveAgentHandlerOfAgent.h" - -class Agent : public Node { - -private: - SensorHandlerOfAgent *sensorHandlerOfAgent; - SlaveAgentHandlerOfAgent *slaveAgentHandlerOfAgent; - MasterAgentHandlerOfAgent *masterAgentHandlerOfAgent; - - void init_agent(); - -public: - Agent(); - Agent(const char *name); - - bool set_sensorHandlerOfAgent(); - bool del_sensorHandlerOfAgent(); - SensorHandlerOfAgent *get_sensorHandlerOfAgent(); - - bool set_slaveAgentHandlerOfAgent(); - bool del_slaveAgentHandlerOfAgent(); - SlaveAgentHandlerOfAgent *get_slaveAgentHandlerOfAgent(); - - bool set_masterAgentHandlerOfAgent(); - bool del_masterAgentHandlerOfAgent(); - MasterAgentHandlerOfAgent *get_masterAgentHandlerOfAgent(); - - void trigger(); -}; - -#endif diff --git a/lib/gen_agent_test2/AgentSlotOfTestbench.cpp b/lib/gen_agent_test2/AgentSlotOfTestbench.cpp deleted file mode 100644 index cc0d7a9..0000000 --- a/lib/gen_agent_test2/AgentSlotOfTestbench.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "AgentSlotOfTestbench.h" - -#include - -void AgentSlotOfTestbench::init_agentSlotOfTestbench() { agent = NULL; } - -AgentSlotOfTestbench::AgentSlotOfTestbench() { init_agentSlotOfTestbench(); } - -bool AgentSlotOfTestbench::set_agent(Agent *agent) { - if (agent != NULL) { - this->agent = agent; - return true; - } - return false; -} - -bool AgentSlotOfTestbench::del_agent() { - if (agent != NULL) { - agent = NULL; - return true; - } - return false; -} - -Agent *AgentSlotOfTestbench::get_agent() { return agent; } diff --git a/lib/gen_agent_test2/AgentSlotOfTestbench.h b/lib/gen_agent_test2/AgentSlotOfTestbench.h deleted file mode 100644 index 61ae48d..0000000 --- a/lib/gen_agent_test2/AgentSlotOfTestbench.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef AGENTSLOTOFTESTBENCH_HEADERFILE -#define AGENTSLOTOFTESTBENCH_HEADERFILE - -#include "Agent.h" - -class AgentSlotOfTestbench { - -protected: - Agent *agent; - - void init_agentSlotOfTestbench(); - -public: - AgentSlotOfTestbench(); - - bool set_agent(Agent *agent); - bool del_agent(); - Agent *get_agent(); -}; - -#endif diff --git a/lib/gen_agent_test2/CMakeLists.txt b/lib/gen_agent_test2/CMakeLists.txt deleted file mode 100644 index 2aacd60..0000000 --- a/lib/gen_agent_test2/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -add_library(ROSAGenAgentTest2 - Agent.cpp - AgentSlotOfTestbench.cpp - attach_modules.cpp - attach_modulesToTestbench.cpp - Channel.cpp - ChannelSlotOfTestbench.cpp - ConfidenceModule.cpp - create_unit.cpp - CSVreaderModule.cpp - HistoryEntry.cpp - HistoryModule.cpp - main.cpp - MasterAgentHandlerOfAgent.cpp - Message.cpp - Module.cpp - mount_nodes.cpp - Node.cpp - printError.cpp - register_in_testbench.cpp - Sensor.cpp - SensorHandlerOfAgent.cpp - SensorSlotOfAgent.cpp - SensorSlotOfTestbench.cpp - SlaveAgentHandlerOfAgent.cpp - SlaveAgentSlotOfAgent.cpp - Slot.cpp - SlotOfAgent.cpp - Testbench.cpp - Unit.cpp - ) - diff --git a/lib/gen_agent_test2/CSVreaderModule.cpp b/lib/gen_agent_test2/CSVreaderModule.cpp deleted file mode 100644 index 90fcd24..0000000 --- a/lib/gen_agent_test2/CSVreaderModule.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "CSVreaderModule.h" -#include "rosa/config/config.h" -#include -#include -#include - -#define STRINGLENGTH 5000 - -void CSVreaderModule::initialize_csvreader(FILE *fpointer, unsigned int column, - unsigned int start_row) { - // fpointer_read = fopen(filepath_read, "r"); - - // TODO: file ponter schon aus CSV-Reader Creator Funktion übergeben.. dann - // kann man nämlich ausgeben, wenn da was nicht erstellt werden kann - // bool file_opened = fopen_s(&fpointer_read, filepath_read, "r"); - // TODO: etwas mit flag - - this->fpointer = fpointer; - this->row = 1; - this->column = column; - this->start_row = start_row; - - flag_csv_reader_configured = true; -} - -CSVreaderModule::CSVreaderModule() { - set_name(NO_NAME); - flag_csv_reader_configured = false; -} - -CSVreaderModule::CSVreaderModule(const char *name) { - set_name(name); - flag_csv_reader_configured = false; -} - -CSVreaderModule::CSVreaderModule(FILE *fpointer, unsigned int column, - unsigned int start_row) { - set_name(NO_NAME); - - if (fpointer) { - initialize_csvreader(fpointer, column, start_row); - } else { - flag_csv_reader_configured = false; - } -} - -CSVreaderModule::CSVreaderModule(const char *name, FILE *fpointer, - unsigned int column, unsigned int start_row) { - set_name(name); - - if (fpointer) { - initialize_csvreader(fpointer, column, start_row); - } else { - flag_csv_reader_configured = false; - } -} -/* -CSV_Reader :: CSV_Reader(char* name, char* filepath_read, int column, int -start_row) { - -} -*/ - -// XXX: Wird nicht mehr benutzt -// TODO: überarbeiten nach folgendem Beispiel -// https://msdn.microsoft.com/en-us/library/ftsafwz3.aspx -bool CSVreaderModule::read_one_row() { - if (fpointer) { - char readrow[STRINGLENGTH] = "" /*, electedfield[STRINGLENGTH] = ""*/; - - // TODO: move following for-loop to "initialize_csvreader(...) - for (; row < start_row; row++) { - - if (!fgets(readrow, STRINGLENGTH, fpointer)) - return false; - } - - if (fgets(readrow, STRINGLENGTH, fpointer)) { - auto strtok_f = -#ifdef ROSA_WINDOWS - strtok_s -#else - strtok_r -#endif - ; - char *ptr, *tokptr; - // TODO: make delimiter configurable! - ptr = strtok_f(readrow, ",;", &tokptr); - // OLD: unsigned int dataset_counter = 0; - dataset_counter = 0; - - if (list_of_datasets[dataset_counter] == 1) { - data_read[dataset_counter] = std::stof(ptr, NULL); - dataset_counter++; - } else { - ptr = strtok_f(NULL, ",;", &tokptr); - } - - for (; dataset_counter < num_of_datasets; dataset_counter++) { - for (unsigned int c_ix = list_of_datasets[dataset_counter - 1]; - c_ix < list_of_datasets[dataset_counter]; c_ix++) { - ptr = strtok_f(NULL, ",;", &tokptr); - } - data_read[dataset_counter] = std::stof(ptr, NULL); - } - return true; - } - } - return false; -} - -float CSVreaderModule::get_value_of_field(unsigned int field) { - // TODO: Bessere Fehlerbehandlung.. also nciht einfach 0 returnen, wenn kein - // richtiges FEld!!! - if (field < num_of_datasets) { - return data_read[field]; - } - - return 0.0; -} - -// TODO: überarbeiten nach folgendem Beispiel -// https://msdn.microsoft.com/en-us/library/ftsafwz3.aspx -bool CSVreaderModule::read_field() { - if (fpointer) { - char readrow[STRINGLENGTH] = "" /*, electedfield[STRINGLENGTH] = ""*/; - - // TODO: move following for-loop to "initialize_csvreader(...) - for (; row < start_row; row++) { - - if (!fgets(readrow, STRINGLENGTH, fpointer)) - return false; - } - - if (fgets(readrow, STRINGLENGTH, fpointer)) { - auto strtok_f = -#ifdef ROSA_WINDOWS - strtok_s -#else - strtok_r -#endif - ; - char *ptr, *tokptr; - // TODO: make delimiter configurable! - ptr = strtok_f(readrow, ",;", &tokptr); - - for (unsigned int d_ix = 1; d_ix < column; d_ix++) { - ptr = strtok_f(NULL, ",;", &tokptr); - } - - input_data = std::stof(ptr, NULL); - return true; - } - } - return false; -} - -bool CSVreaderModule::get_next_value(float *value) { - - if (flag_csv_reader_configured) { - if (read_field()) { - *value = input_data; - return true; - } - } - - return false; -} - -// TODO: flag_csv_reader_configured abfragen -void CSVreaderModule::close_file() { fclose(fpointer); } diff --git a/lib/gen_agent_test2/CSVreaderModule.h b/lib/gen_agent_test2/CSVreaderModule.h deleted file mode 100644 index 880d98a..0000000 --- a/lib/gen_agent_test2/CSVreaderModule.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CSV_READER_HEADERFILE -#define CSV_READER_HEADERFILE - -#include "Module.h" -#include - -class CSVreaderModule : public Module { - -private: - FILE *fpointer; - unsigned int num_of_datasets; - unsigned int list_of_datasets[MAX_NUM_OF_DATA_SETS]; - float data_read[MAX_NUM_OF_DATA_SETS]; - unsigned int row, start_row, column; - float input_data; - bool flag_csv_reader_configured; - unsigned int dataset_counter; - - // private fuctions - void initialize_csvreader(FILE *fpointer, unsigned int column, - unsigned int start_row); - -public: - CSVreaderModule(); - CSVreaderModule(const char *name); - CSVreaderModule(FILE *fpointer, unsigned int column, unsigned int start_row); - CSVreaderModule(const char *name, FILE *fpointer, unsigned int column, - unsigned int start_row); - - bool read_one_row(); - - bool read_field(); - float get_value_of_field(unsigned int field); - - // new functions - bool get_next_value(float *value); - - void close_file(); -}; - -#endif diff --git a/lib/gen_agent_test2/Channel.cpp b/lib/gen_agent_test2/Channel.cpp deleted file mode 100644 index 23336f2..0000000 --- a/lib/gen_agent_test2/Channel.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "Channel.h" -#include - -#define MAX_BUFFER_LENGTH 100 - -void Channel::init_channel() { - maxBufferLength = MAX_BUFFER_LENGTH; - transferRate = MAX_BUFFER_LENGTH; -} - -Channel::Channel() { init_channel(); } - -Channel::Channel(const char *name) { - set_name(name); - init_channel(); -} - -bool Channel::set_maxBufferLength(unsigned int maxBufferLength) { - if (maxBufferLength <= MAX_BUFFER_LENGTH) { - this->maxBufferLength = maxBufferLength; - return true; - } - return false; -} - -unsigned int Channel::get_maxBufferLength() { return maxBufferLength; } - -unsigned int Channel::get_avlInputBufferUp() { - return maxBufferLength - lInputMsgBufferUp.size(); -} - -unsigned int Channel::get_avlOutputBufferUp() { - return maxBufferLength - lOutputMsgBufferUp.size(); -} - -unsigned int Channel::get_avlInputBufferDown() { - return maxBufferLength - lInputMsgBufferDown.size(); -} - -unsigned int Channel::get_avlOutputBufferDown() { - return maxBufferLength - lOutputMsgBufferDown.size(); -} - -bool Channel::set_transferRate(unsigned int transferRate) { - if (transferRate <= MAX_BUFFER_LENGTH) { - this->transferRate = transferRate; - return true; - } - return false; -} - -unsigned int Channel::get_transferRate() { return transferRate; } - -bool Channel::add_msgAtBegin(list *buffer, Message *message) { - try { - buffer->push_front(message); - } catch (bad_alloc &error) { - delete message; - return false; - } - return true; -} - -bool Channel::del_msgAtBegin(list *buffer) { - try { - buffer->pop_front(); - } catch (bad_alloc &error) { - return false; - } - return true; -} - -bool Channel::add_msgAtEnd(list *buffer, Message *message) { - try { - buffer->push_back(message); - } catch (bad_alloc &error) { - delete message; - return false; - } - return true; -} - -bool del_msgAtEnd(list *buffer) { - try { - buffer->pop_back(); - } catch (bad_alloc &error) { - return false; - } - return true; -} - -bool Channel::send_MsgUp(Message *message) { - if (message != NULL) { - if (transferRate == 0) { - // TODO: at the moment only one packet (in the front) gets deleted if - // buffer is full. However, the whole message (instruction+value) should - // be deleted in case of a full buffer - if (lOutputMsgBufferUp.size() == maxBufferLength) { - del_msgAtBegin(&lOutputMsgBufferUp); - } - return add_msgAtEnd(&lOutputMsgBufferUp, message); - } else { - if (lInputMsgBufferUp.size() == maxBufferLength) { - // TODO: at the moment only one packet (in the front) gets deleted if - // buffer is full. However, the whole message (instruction+value) should - // be deleted in case of a full buffer - del_msgAtBegin(&lInputMsgBufferUp); - } - return add_msgAtEnd(&lInputMsgBufferUp, message); - } - } - // FIXME - return false; -} - -bool Channel::send_MsgUp(float msg) { - Message *message = new Message(msg); - return send_MsgUp(message); -} - -bool Channel::send_MsgUp(int msg) { - Message *message = new Message(msg); - return send_MsgUp(message); -} - -bool Channel::get_MsgUp(float *msg) { - if (isThereFloatMsgUp()) { - float tempMsg; - if (lOutputMsgBufferUp.front()->getMsg(&tempMsg)) { - *msg = tempMsg; - del_msgAtBegin(&lOutputMsgBufferUp); - return true; - } - } - return false; -} - -bool Channel::get_MsgUp(int *msg) { - if (isThereIntMsgUp()) { - int tempMsg; - if (lOutputMsgBufferUp.front()->getMsg(&tempMsg)) { - *msg = tempMsg; - del_msgAtBegin(&lOutputMsgBufferUp); - return true; - } - } - return false; -} - -bool Channel::isThereFloatMsgUp() { - if (lOutputMsgBufferUp.size() > 0) { - if (lOutputMsgBufferUp.front() != NULL) { - return lOutputMsgBufferUp.front()->isMsgFloat(); - } - } - return false; -} - -bool Channel::isThereIntMsgUp() { - if (lOutputMsgBufferUp.size() > 0) { - if (lOutputMsgBufferUp.front() != NULL) { - return lOutputMsgBufferUp.front()->isMsgInt(); - } - } - return false; -} - -bool Channel::send_MsgDown(Message *message) { - if (message != NULL) { - if (transferRate == 0) { - if (lOutputMsgBufferDown.size() == maxBufferLength) { - del_msgAtBegin(&lOutputMsgBufferDown); - } - return add_msgAtEnd(&lOutputMsgBufferDown, message); - } else { - if (lInputMsgBufferDown.size() == maxBufferLength) { - del_msgAtBegin(&lInputMsgBufferDown); - } - return add_msgAtEnd(&lInputMsgBufferDown, message); - } - } - // FIXME - return false; -} - -bool Channel::send_MsgDown(float msg) { - Message *message = new Message(msg); - return send_MsgDown(message); -} - -bool Channel::send_MsgDown(int msg) { - Message *message = new Message(msg); - return send_MsgDown(message); -} - -bool Channel::get_MsgDown(float *msg) { - if (isThereFloatMsgDown()) { - float tempMsg; - if (lOutputMsgBufferDown.front()->getMsg(&tempMsg)) { - *msg = tempMsg; - del_msgAtBegin(&lOutputMsgBufferDown); - return true; - } - } - return false; -} - -bool Channel::get_MsgDown(int *msg) { - if (isThereIntMsgDown()) { - int tempMsg; - if (lOutputMsgBufferDown.front()->getMsg(&tempMsg)) { - *msg = tempMsg; - del_msgAtBegin(&lOutputMsgBufferDown); - return true; - } - } - return false; -} - -bool Channel::isThereFloatMsgDown() { - if (lOutputMsgBufferDown.size() > 0) { - if (lOutputMsgBufferDown.front() != NULL) { - return lOutputMsgBufferDown.front()->isMsgFloat(); - } - } - return false; -} - -bool Channel::isThereIntMsgDown() { - if (lOutputMsgBufferDown.size() > 0) { - if (lOutputMsgBufferDown.front() != NULL) { - return lOutputMsgBufferDown.front()->isMsgInt(); - } - } - return false; -} - -bool Channel::transferMsgs(list *dest_buffer, - list *src_buffer) { - unsigned int NumOfMsgsToMove; - - if (transferRate <= src_buffer->size()) { - NumOfMsgsToMove = transferRate; - } else { - NumOfMsgsToMove = src_buffer->size(); - } - - if (NumOfMsgsToMove <= maxBufferLength - dest_buffer->size()) { - for (unsigned int i = 0; i < NumOfMsgsToMove; i++) { - if (add_msgAtEnd(dest_buffer, src_buffer->front())) { - if (!del_msgAtBegin(src_buffer)) { - return false; - } - } else { - return false; - } - } - return true; - } - return false; -} - -bool Channel::trigger() { - bool flag_worked = transferMsgs(&lOutputMsgBufferUp, &lInputMsgBufferUp) && - transferMsgs(&lOutputMsgBufferUp, &lInputMsgBufferUp); - printf("Channel %s: in_up %zu, out_up %zu, in_dn %zu, out_dn %zu,\n", name, - lInputMsgBufferUp.size(), lOutputMsgBufferUp.size(), - lInputMsgBufferDown.size(), lOutputMsgBufferDown.size()); - return flag_worked; -} diff --git a/lib/gen_agent_test2/Channel.h b/lib/gen_agent_test2/Channel.h deleted file mode 100644 index 4924927..0000000 --- a/lib/gen_agent_test2/Channel.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef CHANNEL_HEADERFILE -#define CHANNEL_HEADERFILE - -#include "Message.h" -#include "Module.h" -#include - -#define MAX_BUFFER_LENGTH 100 -#define OPEN NULL - -using namespace std; - -class Channel : public Module { - -private: - list lInputMsgBufferUp; - list lOutputMsgBufferUp; - - list lInputMsgBufferDown; - list lOutputMsgBufferDown; - - unsigned int maxBufferLength; - unsigned int transferRate; - - void init_channel(); - - bool add_msgAtBegin(list *buffer, Message *message); - bool del_msgAtBegin(list *buffer); - - bool add_msgAtEnd(list *buffer, Message *message); - bool del_msgAtEnd(list *buffer); - -public: - Channel(); - Channel(const char *name); - - bool set_maxBufferLength(unsigned int maxBufferLength); - unsigned int get_maxBufferLength(); - - unsigned int get_avlInputBufferUp(); - unsigned int get_avlOutputBufferUp(); - unsigned int get_avlInputBufferDown(); - unsigned int get_avlOutputBufferDown(); - - bool set_transferRate(unsigned int transferRate); - unsigned int get_transferRate(); - - bool send_MsgUp(Message *message); - bool send_MsgUp(float msg); - bool send_MsgUp(int msg); - bool get_MsgUp(float *msg); - bool get_MsgUp(int *msg); - bool isThereFloatMsgUp(); - bool isThereIntMsgUp(); - - bool send_MsgDown(Message *message); - bool send_MsgDown(float msg); - bool send_MsgDown(int msg); - bool get_MsgDown(float *msg); - bool get_MsgDown(int *msg); - bool isThereFloatMsgDown(); - bool isThereIntMsgDown(); - - bool trigger(); - bool transferMsgs(list *dest_buffer, list *src_buffer); -}; - -#endif diff --git a/lib/gen_agent_test2/ChannelSlotOfTestbench.cpp b/lib/gen_agent_test2/ChannelSlotOfTestbench.cpp deleted file mode 100644 index 7ecd799..0000000 --- a/lib/gen_agent_test2/ChannelSlotOfTestbench.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "ChannelSlotOfTestbench.h" - -#include - -void ChannelSlotOfTestbench::init_channelSlotOfTestbench() { channel = NULL; } - -ChannelSlotOfTestbench::ChannelSlotOfTestbench() { - init_channelSlotOfTestbench(); -} - -bool ChannelSlotOfTestbench::set_channel(Channel *channel) { - if (channel != NULL) { - this->channel = channel; - return true; - } - return false; -} - -bool ChannelSlotOfTestbench::del_channel() { - if (channel != NULL) { - channel = NULL; - return true; - } - return false; -} - -Channel *ChannelSlotOfTestbench::get_channel() { return channel; } diff --git a/lib/gen_agent_test2/ChannelSlotOfTestbench.h b/lib/gen_agent_test2/ChannelSlotOfTestbench.h deleted file mode 100644 index 472e304..0000000 --- a/lib/gen_agent_test2/ChannelSlotOfTestbench.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CHANNELSLOTOFTESTBENCH_HEADERFILE -#define CHANNELSLOTOFTESTBENCH_HEADERFILE - -#include "Channel.h" - -class ChannelSlotOfTestbench { - -protected: - Channel *channel; - - void init_channelSlotOfTestbench(); - -public: - ChannelSlotOfTestbench(); - - bool set_channel(Channel *channel); - bool del_channel(); - Channel *get_channel(); -}; - -#endif diff --git a/lib/gen_agent_test2/ConfidenceModule.cpp b/lib/gen_agent_test2/ConfidenceModule.cpp deleted file mode 100644 index 6b31c32..0000000 --- a/lib/gen_agent_test2/ConfidenceModule.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "ConfidenceModule.h" -#include "HistoryModule.h" - -#include - -// TODO: at the moment are only positive rates_of_changes allowed!! -void ConfidenceModule::initialize_confidence_validator( - float lower_bound, bool flag_lower_bound_exist, float upper_bound, - bool flag_upper_bound_exist, float rates_of_change, - bool flag_rates_of_change_exist) { - // plausibility - if (lower_bound <= upper_bound) { - this->lower_bound = lower_bound; - this->upper_bound = upper_bound; - this->flag_lower_bound_exist = flag_lower_bound_exist; - this->flag_upper_bound_exist = flag_upper_bound_exist; - } else { - this->lower_bound = upper_bound; - this->upper_bound = lower_bound; - this->flag_lower_bound_exist = flag_upper_bound_exist; - this->flag_upper_bound_exist = flag_lower_bound_exist; - } - - // consistency - this->rates_of_change = rates_of_change; - this->flag_rates_of_change_exist = flag_rates_of_change_exist; - flag_value_got_inconsistence = false; - - // TODO: Changes of Other Sensors (e.g. Environment Temperature Sensor) -} - -ConfidenceModule::ConfidenceModule(float lower_bound, - bool flag_lower_bound_exist, - float upper_bound, - bool flag_upper_bound_exist, - float rates_of_change, - bool flag_rates_of_change_exist) { - set_name(NO_NAME); - initialize_confidence_validator(lower_bound, flag_lower_bound_exist, - upper_bound, flag_upper_bound_exist, - rates_of_change, flag_rates_of_change_exist); -} - -ConfidenceModule::ConfidenceModule(char *name, float lower_bound, - bool flag_lower_bound_exist, - float upper_bound, - bool flag_upper_bound_exist, - float rates_of_change, - bool flag_rates_of_change_exist) { - set_name(name); - initialize_confidence_validator(lower_bound, flag_lower_bound_exist, - upper_bound, flag_upper_bound_exist, - rates_of_change, flag_rates_of_change_exist); -} - -bool ConfidenceModule::validate_confidence( - float input /*, HistoryModule* historyModule*/) { - - bool flag_confidence = true; - - // bounds - if (flag_lower_bound_exist && input < lower_bound) { - flag_confidence = false; - // printf("lb\ninput = %f\n", input); - } - - if (flag_upper_bound_exist && input > upper_bound) { - flag_confidence = false; - // printf("ub\n"); - } - - // rates_of_change - float trend_abs = .0; - // TODO: time_unites and time_base should be configurable and saved for the - // object - // unsigned int time_units = 2; - bool got_trend = - false; // XXX historyModule->get_history_trend_absolutely(&trend_abs, - // time_units, TB_SECONDS); - - if (got_trend) { - if (trend_abs > rates_of_change) { - flag_confidence = false; - // printf("trend\n"); - - // VERSUCH - if (flag_value_got_inconsistence == false) { - // printf("setze flag\n"); - flag_value_got_inconsistence = true; - value_before_value_got_inconsistence = - 0; // XXX historyModule->get_value_ago(time_units); - } - } - } else { - // printf("no trend\n"); - } - - if (flag_value_got_inconsistence) { - - // TODO: nicht hardcoded - float seconds = 20; - - // printf("tradition\n"); - - if (input == value_before_value_got_inconsistence) { - flag_value_got_inconsistence = false; - } else if (input < value_before_value_got_inconsistence) { - if (input >= - value_before_value_got_inconsistence - rates_of_change * seconds) { - flag_value_got_inconsistence = false; - } else { - flag_confidence = false; - } - } else if (input > value_before_value_got_inconsistence) { - if (input <= - value_before_value_got_inconsistence + rates_of_change * seconds) { - flag_value_got_inconsistence = false; - } else { - flag_confidence = false; - } - } else { - flag_confidence = false; - } - } - - confidence = flag_confidence; - return confidence; -} - -bool ConfidenceModule::get_confidence() { return confidence; } - -void ConfidenceModule::set_lower_bound(float lower_bound) { - this->lower_bound = lower_bound; -} - -float ConfidenceModule::get_lower_bound() { return lower_bound; } - -void ConfidenceModule::set_flag_lower_bound_exist(bool flag) { - this->flag_lower_bound_exist = flag; -} - -bool ConfidenceModule::get_flag_lower_bound_exist() { - return flag_lower_bound_exist; -} - -void ConfidenceModule::set_upper_bound(float upper_bound) { - this->upper_bound = upper_bound; -} - -float ConfidenceModule::get_upper_bound() { return upper_bound; } - -void ConfidenceModule::set_flag_upper_bound_exist(bool flag) { - this->flag_upper_bound_exist = flag; -} - -bool ConfidenceModule::get_flag_upper_bound_exist() { - return flag_upper_bound_exist; -} - -void ConfidenceModule::set_rates_of_change(float rates) { - this->rates_of_change = rates; -} - -float ConfidenceModule::get_rates_of_change() { return rates_of_change; } - -void ConfidenceModule::set_flag_rates_of_change_exist(bool flag) { - this->flag_rates_of_change_exist = flag; -} - -bool ConfidenceModule::get_flag_rates_of_change_exist() { - return flag_rates_of_change_exist; -} diff --git a/lib/gen_agent_test2/ConfidenceModule.h b/lib/gen_agent_test2/ConfidenceModule.h deleted file mode 100644 index 45295c6..0000000 --- a/lib/gen_agent_test2/ConfidenceModule.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef PLAUSIBILITY_HEADERFILE -#define PLAUSIBILITY_HEADERFILE - -#include "HistoryModule.h" -#include "Module.h" - -class ConfidenceModule : public Module { - -private: - bool confidence; - - // plausibility - float lower_bound, upper_bound; - bool flag_lower_bound_exist, flag_upper_bound_exist; - - // consistency - float rates_of_change; - bool flag_rates_of_change_exist; - float value_before_value_got_inconsistence; - bool flag_value_got_inconsistence; - - // TODO: Changes of Other Sensors (e.g. Environment Temperature Sensor) - - // private functions - void initialize_confidence_validator(float lower_bound, - bool flag_lower_bound_exist, - float upper_bound, - bool flag_upper_bound_exist, - float rates_of_change, - bool flag_rates_of_change_exist); - -public: - ConfidenceModule(float lower_bound, bool flag_lower_bound_exist, - float upper_bound, bool flag_upper_bound_exist, - float rates_of_change, bool flag_rates_of_change_exist); - ConfidenceModule(char *name, float lower_bound, bool flag_lower_bound_exist, - float upper_bound, bool flag_upper_bound_exist, - float rates_of_change, bool flag_rates_of_change_exist); - - bool validate_confidence(float input /*, HistoryModule* historyModule*/); - bool get_confidence(); - - void set_lower_bound(float lower_bound); - float get_lower_bound(); - - void set_flag_lower_bound_exist(bool flag); - bool get_flag_lower_bound_exist(); - - void set_upper_bound(float upper_bound); - float get_upper_bound(); - - void set_flag_upper_bound_exist(bool flag); - bool get_flag_upper_bound_exist(); - - void set_rates_of_change(float rates); - float get_rates_of_change(); - - void set_flag_rates_of_change_exist(bool flag); - bool get_flag_rates_of_change_exist(); -}; - -#endif diff --git a/lib/gen_agent_test2/HistoryEntry.cpp b/lib/gen_agent_test2/HistoryEntry.cpp deleted file mode 100644 index 0306671..0000000 --- a/lib/gen_agent_test2/HistoryEntry.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "HistoryEntry.h" - -HistoryEntry::HistoryEntry() {} - -void HistoryEntry::set_entryValue(float entryValue) { - this->entryValue = entryValue; -} - -float HistoryEntry::get_entryValue() { return entryValue; } diff --git a/lib/gen_agent_test2/HistoryEntry.h b/lib/gen_agent_test2/HistoryEntry.h deleted file mode 100644 index 360db5c..0000000 --- a/lib/gen_agent_test2/HistoryEntry.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HISTORYENTRY_HEADERFILE -#define HISTORYENTRY_HEADERFILE - -// TODO: save also time stamp or something similar -class HistoryEntry { - -private: - float entryValue; - -public: - HistoryEntry(); - - void set_entryValue(float entryValue); - float get_entryValue(); -}; - -#endif diff --git a/lib/gen_agent_test2/HistoryModule.cpp b/lib/gen_agent_test2/HistoryModule.cpp deleted file mode 100644 index f7d73f6..0000000 --- a/lib/gen_agent_test2/HistoryModule.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "HistoryModule.h" -#include "printError.h" -#include - -#define MAX_HIST_LENGTH 1000 - -// using namespace std; - -void HistoryModule::initHistoryModule() { - if (MAX_HIST_LENGTH <= vHistory.max_size()) { - historyLength = MAX_HIST_LENGTH; - } else { - historyLength = vHistory.max_size(); - } - - delimitationMode = DELIMITATE_MODE_SRWF; -} - -HistoryModule::HistoryModule() { - set_name(NO_NAME); - initHistoryModule(); -} - -HistoryModule::HistoryModule(const char *name) { - initHistoryModule(); - set_name(name); -} - -bool HistoryModule::set_maxHistoryLength(unsigned int length) { - if (length <= MAX_HIST_LENGTH && length <= vHistory.max_size()) { - // this->historyLength = historyLength; - historyLength = length; - return true; - } - return false; -} - -unsigned int HistoryModule::get_maxHistoryLength() { return historyLength; } - -bool HistoryModule::set_delimitationMode(int delimitationMode) { - if (delimitationMode > DELIMITATE_MODE_LBOUND && - delimitationMode < DELIMITATE_MODE_UBOUND) { - this->delimitationMode = delimitationMode; - return true; - } - return false; -} - -int HistoryModule::get_delimitationMode() { return delimitationMode; } - -bool HistoryModule::add_entry(float entryValue) { - if (vHistory.size() <= historyLength) { - HistoryEntry *historyEntry = new HistoryEntry(); - if (historyEntry != NULL) { - historyEntry->set_entryValue(entryValue); - try { - vHistory.push_back(historyEntry); - return true; - } catch (bad_alloc &error) { - printError("bad_alloc caught: ", error.what()); - } - } else { - printError("Couldn't create HistoryEntry!"); - } - } else { - switch (delimitationMode) { - case DELIMITATE_MODE_SRWF: - printError("History is already full!"); - break; - default: - printError("History is already full! DelimitationMode isn't set!"); - break; - } - } - return false; -} - -unsigned int HistoryModule::get_numberOfEntries() { return vHistory.size(); } - diff --git a/lib/gen_agent_test2/HistoryModule.h b/lib/gen_agent_test2/HistoryModule.h deleted file mode 100644 index ec0765a..0000000 --- a/lib/gen_agent_test2/HistoryModule.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef HISTORYMODULE_HEADERFILE -#define HISTORYMODULE_HEADERFILE - -#include "HistoryEntry.h" -#include "Module.h" -#include - -#define DELIMITATE_MODE_LBOUND 0 -#define DELIMITATE_MODE_SRWF 1 // Stop Recording When Full -#define DELIMITATE_MODE_FIFO 2 // First In First Out -#define DELIMITATE_MODE_LIFO 3 // Last In First Out -#define DELIMITATE_MODE_UBOUND 4 - -using namespace std; - -class HistoryModule : public Module { - -private: - vector vHistory; - unsigned int historyLength; - int delimitationMode; - - void initHistoryModule(); - -public: - HistoryModule(); - HistoryModule(const char *name); - - bool set_maxHistoryLength(unsigned int length); - unsigned int get_maxHistoryLength(); - - bool set_delimitationMode(int delimitationMode); - int get_delimitationMode(); - - bool add_entry(float entryValue); - unsigned int get_numberOfEntries(); -}; - -#endif diff --git a/lib/gen_agent_test2/MasterAgentHandlerOfAgent.cpp b/lib/gen_agent_test2/MasterAgentHandlerOfAgent.cpp deleted file mode 100644 index a52b2cb..0000000 --- a/lib/gen_agent_test2/MasterAgentHandlerOfAgent.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "MasterAgentHandlerOfAgent.h" -#include - -#define MAX_BUFFER_LENGTH_MASTERAGENT_HANDLER 300 - -MasterAgentHandlerOfAgent::MasterAgentHandlerOfAgent() { - masterAgentSlotOfAgent = NULL; - maxBufferLength = MAX_BUFFER_LENGTH_MASTERAGENT_HANDLER; -} - -bool MasterAgentHandlerOfAgent::mount_masterAgentIntoSlaveAgentSlot( - Channel *comPort) { - masterAgentSlotOfAgent = new SlotOfAgent(); - if (masterAgentSlotOfAgent != NULL) { - if (masterAgentSlotOfAgent->set_comPort(comPort)) { - return true; - } - } - delete masterAgentSlotOfAgent; - return false; -} - -SlotOfAgent *MasterAgentHandlerOfAgent::get_masterAgentSlotAddress() { - return masterAgentSlotOfAgent; -} - -bool MasterAgentHandlerOfAgent::demount_masterAgent() { - if (masterAgentSlotOfAgent != NULL) { - delete masterAgentSlotOfAgent; - masterAgentSlotOfAgent = NULL; - return true; - } - return false; -} - -bool MasterAgentHandlerOfAgent::set_maxBufferLength( - unsigned int maxBufferLength) { - if (maxBufferLength <= MAX_BUFFER_LENGTH_MASTERAGENT_HANDLER) { - this->maxBufferLength = maxBufferLength; - return true; - } - return false; -} - -unsigned int MasterAgentHandlerOfAgent::get_maxBufferLength() { - return maxBufferLength; -} - -bool MasterAgentHandlerOfAgent::pass_msgToSendBuffer(float msg) { - // TODO: make message handler and shift following lines to it! - // TODO: try/catch for pushback function! - Message *message = new Message(msg); - lSendBuffer.push_back(message); - return false; -} - -bool MasterAgentHandlerOfAgent::pass_msgToSendBuffer(int msg) { - // TODO: make message handler and shift following lines to it! - // TODO: try/catch for pushback function! - Message *message = new Message(msg); - lSendBuffer.push_back(message); - return false; -} - -unsigned int MasterAgentHandlerOfAgent::get_avlSendBuffer() { - return maxBufferLength - get_occSendBuffer(); -} - -unsigned int MasterAgentHandlerOfAgent::get_occSendBuffer() { - return lSendBuffer.size(); -} - -bool MasterAgentHandlerOfAgent::send_msgs() { - if (masterAgentSlotOfAgent != NULL) { - Channel *comPort = masterAgentSlotOfAgent->get_comPort(); - if (comPort != NULL) { - // TODO: also other sending mode... current MODE: only send it when all - // packets can be sended - if (get_occSendBuffer() <= comPort->get_avlInputBufferUp()) { - // for(unsigned int i=0; i 0) { - // TODO: make message handler and shift following lines to it! - // TODO: try/catch for pushback function! - comPort->send_MsgUp(lSendBuffer.front()); - lSendBuffer.pop_front(); - } - } - } - } - return false; -} diff --git a/lib/gen_agent_test2/MasterAgentHandlerOfAgent.h b/lib/gen_agent_test2/MasterAgentHandlerOfAgent.h deleted file mode 100644 index ba8318f..0000000 --- a/lib/gen_agent_test2/MasterAgentHandlerOfAgent.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef MASTERAGENTHANDLEROFAGENT_HEADERFILE -#define MASTERAGENTHANDLEROFAGENT_HEADERFILE - -#include "SlotOfAgent.h" -#include "Unit.h" - -class MasterAgentHandlerOfAgent : public Unit { - -private: - SlotOfAgent *masterAgentSlotOfAgent; - - list lSendBuffer; - unsigned int maxBufferLength; - -public: - MasterAgentHandlerOfAgent(); - - bool mount_masterAgentIntoSlaveAgentSlot(Channel *comPort); - SlotOfAgent *get_masterAgentSlotAddress(); - bool demount_masterAgent(); - - bool set_maxBufferLength(unsigned int maxBufferLength); - unsigned int get_maxBufferLength(); - - bool pass_msgToSendBuffer(float msg); - bool pass_msgToSendBuffer(int msg); - unsigned int get_avlSendBuffer(); - unsigned int get_occSendBuffer(); - bool send_msgs(); -}; - -#endif diff --git a/lib/gen_agent_test2/Message.cpp b/lib/gen_agent_test2/Message.cpp deleted file mode 100644 index 6a2014b..0000000 --- a/lib/gen_agent_test2/Message.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "Message.h" - -#include - -#define MSG_IS_FLOAT true -#define MSG_IS_INT false - -Message::Message(float msg) { - messageType = MSG_IS_FLOAT; - fMsg = msg; -} - -Message::Message(int msg) { - messageType = MSG_IS_INT; - iMsg = msg; -} - -bool Message::isMsgFloat() { - if (messageType == MSG_IS_FLOAT) { - return true; - } - - if (messageType == MSG_IS_INT) { - return false; - } - - return false; -} - -bool Message::isMsgInt() { - if (messageType == MSG_IS_INT) { - return true; - } - return false; -} - -bool Message::getMsg(float *msg) { - if (messageType == MSG_IS_FLOAT) { - *msg = fMsg; - return true; - } - return false; -} - -bool Message::getMsg(int *msg) { - if (messageType == MSG_IS_INT) { - *msg = iMsg; - return true; - } - return false; -} diff --git a/lib/gen_agent_test2/Message.h b/lib/gen_agent_test2/Message.h deleted file mode 100644 index d00281b..0000000 --- a/lib/gen_agent_test2/Message.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MESSAGE_HEADERFILE -#define MESSAGE_HEADERFILE - -class Message { - -private: - bool messageType; - float fMsg; - int iMsg; - -public: - Message(float msg); - Message(int msg); - - bool isMsgFloat(); - bool isMsgInt(); - - bool getMsg(float *msg); - bool getMsg(int *msg); -}; - -#endif diff --git a/lib/gen_agent_test2/Module.cpp b/lib/gen_agent_test2/Module.cpp deleted file mode 100644 index 2da1f43..0000000 --- a/lib/gen_agent_test2/Module.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "Module.h" -#include "rosa/config/config.h" -#include - -Module::Module() { set_name(NO_NAME); } - -Module::Module(const char *name) { set_name(name); } - -void Module::set_name(const char *name) { -#ifdef ROSA_WINDOWS - strncpy_s(this->name, MAX_LENGTH_NAME, name, MAX_LENGTH_NAME); -#else - strncpy(this->name, name, MAX_LENGTH_NAME); -#endif -} - -const char *Module::get_name() { return this->name; } diff --git a/lib/gen_agent_test2/Module.h b/lib/gen_agent_test2/Module.h deleted file mode 100644 index fe31888..0000000 --- a/lib/gen_agent_test2/Module.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MODULE_HEADERFILE -#define MODULE_HEADERFILE - -#include "Unit.h" - -class Module : public Unit { - -protected: - char name[MAX_LENGTH_NAME]; - -public: - Module(); - Module(const char *name); - - void set_name(const char *name); - const char *get_name(); -}; - -#endif diff --git a/lib/gen_agent_test2/Node.cpp b/lib/gen_agent_test2/Node.cpp deleted file mode 100644 index a35fe75..0000000 --- a/lib/gen_agent_test2/Node.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "Node.h" - -#define MAX_WORKCYCLE 4294967295 - -Node::Node() {} - -bool Node::set_workingCycle(unsigned int workingCycle) { - if (workingCycle <= MAX_WORKCYCLE) { - this->workingCycle = workingCycle; - return true; - } - return false; -} - -unsigned int Node::get_workingCycle() { return workingCycle; } - diff --git a/lib/gen_agent_test2/Node.h b/lib/gen_agent_test2/Node.h deleted file mode 100644 index 7f4f4e8..0000000 --- a/lib/gen_agent_test2/Node.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NODE_HEADERFILE -#define NODE_HEADERFILE - -#include "Module.h" - -#define ACTIVATED true -#define DEACTIVATED false - -class Node : public Module { - -private: - unsigned int workingCycle; - -public: - Node(); - - bool set_workingCycle(unsigned int workingCycle); - unsigned int get_workingCycle(); -}; - -#endif - diff --git a/lib/gen_agent_test2/Sensor.cpp b/lib/gen_agent_test2/Sensor.cpp deleted file mode 100644 index 6d3b552..0000000 --- a/lib/gen_agent_test2/Sensor.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "Sensor.h" -#include - -void Sensor::initialize_sensor() { - this->flag_masteragent_is_mounted = UNMOUNTED; - this->flag_masteragent_outputport_is_active = INACTIVE; - this->flag_sensor_value_is_valid = INVALID; - this->flag_sensor_value_has_changed = NO; - this->flag_send_value_only_when_changed = NO; -} - -Sensor::Sensor() { - set_name(NO_NAME); - initialize_sensor(); -} - -Sensor::Sensor(const char *name) { - set_name(name); - initialize_sensor(); -} - -// ----- Runtime Functions ----- -void Sensor::set_sensorValue(float sensor_value) { - if (this->sensor_value != sensor_value) { - flag_sensor_value_has_changed = YES; - } - flag_sensor_value_is_valid = VALID; - this->sensor_value = sensor_value; - - printf("Sensor %s updated with: %f\n", name, sensor_value); -} - -float Sensor::get_sensorValue() { return sensor_value; } - -void Sensor::trigger() { - // TODO: difference int and float - if (this->flag_sensor_value_is_valid && this->flag_masteragent_is_mounted && - this->flag_masteragent_outputport_is_active) { - if (flag_send_value_only_when_changed) { - if (flag_sensor_value_has_changed) { - mounted_masteragent_outputport->send_MsgUp(sensor_value); - flag_sensor_value_has_changed = NO; - } - } else { - mounted_masteragent_outputport->send_MsgUp(sensor_value); - flag_sensor_value_has_changed = NO; - } - } -} - -// ----- Setup Functions ----- -bool Sensor::mount_agent(Channel *outputport) { - if (outputport != NULL) { - this->mounted_masteragent_outputport = outputport; - this->flag_masteragent_is_mounted = MOUNTED; - this->flag_masteragent_outputport_is_active = ACTIVE; - return true; - } - return false; -} - -void Sensor::set_flag_send_value_only_when_changed( - bool flag_send_value_only_when_changed) { - this->flag_send_value_only_when_changed = flag_send_value_only_when_changed; -} - -bool Sensor::get_flag_send_value_only_when_changed() { - return this->flag_send_value_only_when_changed; -} - -// ----- set/get ----- -void Sensor::set_flag_sensor_value_is_valid(bool flag_sensor_value_is_valid) { - this->flag_sensor_value_is_valid = flag_sensor_value_is_valid; -} - -bool Sensor::get_flag_sensor_value_is_valid() { - return this->flag_sensor_value_is_valid; -} - -void Sensor::set_flag_sensor_value_has_changed( - bool flag_sensor_value_has_changed) { - this->flag_sensor_value_has_changed = flag_sensor_value_has_changed; -} - -bool Sensor::get_flag_sensor_value_has_changed() { - return this->flag_sensor_value_has_changed; -} - -void Sensor::set_active_state_flag(bool flag) { active_state_flag = flag; } -bool Sensor::get_active_state_flag() { return active_state_flag; } - -float Sensor::get_hardcoded_threshold(unsigned int score, - unsigned int boundary) { - return hardcoded_thresholds[score][boundary]; -} -void Sensor::set_hardcoded_threshold(unsigned int score, unsigned int boundary, - float value) { - hardcoded_thresholds[score][boundary] = value; -} - -float Sensor::get_learned_threshold(unsigned int score, unsigned int boundary) { - return learned_thresholds[score][boundary]; -} -void Sensor::set_learned_threshold(unsigned int score, unsigned int boundary, - float value) { - learned_thresholds[score][boundary] = value; -} - -void Sensor::set_flag_learned_boundary_exist(unsigned int score, - unsigned int boundary, bool flag) { - flag_learned_boundary_exist[score][boundary] = flag; -} -bool Sensor::get_flag_learned_boundary_exist(unsigned int score, - unsigned int boundary) { - return flag_learned_boundary_exist[score][boundary]; -} - -void Sensor::set_flag_use_learned_data(bool flag) { - flag_use_learned_data = flag; -} -bool Sensor::get_flag_use_learned_data() { return flag_use_learned_data; } diff --git a/lib/gen_agent_test2/Sensor.h b/lib/gen_agent_test2/Sensor.h deleted file mode 100644 index dbbfe54..0000000 --- a/lib/gen_agent_test2/Sensor.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef SENSOR_HEADERFILE -#define SENSOR_HEADERFILE - -#include "Channel.h" -#include "Node.h" - -#define MAX_NUM_OF_SCORES 10 - -#define LOWER_BOUNDARY 0 -#define UPPER_BOUNDARY 1 - -#define LEARNED_BOUNDARY_DOES_EXIST true -#define LEARNED_BOUNDARY_DOESNT_EXIST false - -#define USE_LEARNED_DATA true -#define DONT_USE_LEARNED_DATA false - -#define VALID true -#define INVALID false - -class Sensor : public Node { - -private: - // ----- Runtime ----- - float sensor_value; - bool flag_sensor_value_is_valid; - bool flag_sensor_value_has_changed; - - // ----- Setup Master ----- - bool flag_masteragent_is_mounted; - Channel *mounted_masteragent_outputport; - bool flag_masteragent_outputport_is_active; // unnötig? - - // ----- Setup Behavior ----- - bool flag_send_value_only_when_changed; - - // noch nicht überarbeitet - bool active_state_flag; - - float hardcoded_thresholds[MAX_NUM_OF_SCORES][2]; - float learned_thresholds[MAX_NUM_OF_SCORES][2]; - bool flag_learned_boundary_exist[MAX_NUM_OF_SCORES][2]; - - bool flag_use_learned_data; - - void initialize_sensor(); - -public: - Sensor(); - Sensor(const char *name); - - // ----- Runtime Functions ----- - void set_sensorValue(float sensor_value); - float get_sensorValue(); - void trigger(); - - // ----- Setup ----- - bool mount_agent(Channel *outputport); - - void - set_flag_send_value_only_when_changed(bool flag_send_value_only_when_changed); - bool get_flag_send_value_only_when_changed(); - - /* - void set_sensor_id(unsigned int id); - unsigned int get_sensor_id(); - */ - - // ----- set/get ----- - void set_flag_sensor_value_is_valid(bool flag_sensor_value_is_valid); - bool get_flag_sensor_value_is_valid(); - void set_flag_sensor_value_has_changed(bool flag_sensor_value_has_changed); - bool get_flag_sensor_value_has_changed(); - - void set_active_state_flag(bool flag); - bool get_active_state_flag(); - - float get_hardcoded_threshold(unsigned int score, unsigned int boundary); - void set_hardcoded_threshold(unsigned int score, unsigned int boundary, - float value); - - float get_learned_threshold(unsigned int score, unsigned int boundary); - void set_learned_threshold(unsigned int score, unsigned int boundary, - float value); - - void set_flag_learned_boundary_exist(unsigned int score, - unsigned int boundary, bool flag); - bool get_flag_learned_boundary_exist(unsigned int score, - unsigned int boundary); - - void set_flag_use_learned_data(bool flag); - bool get_flag_use_learned_data(); -}; - -#endif diff --git a/lib/gen_agent_test2/SensorHandlerOfAgent.cpp b/lib/gen_agent_test2/SensorHandlerOfAgent.cpp deleted file mode 100644 index bd2b570..0000000 --- a/lib/gen_agent_test2/SensorHandlerOfAgent.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "SensorHandlerOfAgent.h" -#include "printError.h" -#include - -#include - -#define MAXNUMOF_MOUNTEDSENSORS 100 - -using namespace std; - -SensorHandlerOfAgent::SensorHandlerOfAgent() { init_sensorHandler(); } - -void SensorHandlerOfAgent::init_sensorHandler() { - maxNumOf_mountedSensors = MAXNUMOF_MOUNTEDSENSORS; -} - -// TODO: if(vMountedSensors.size() < maxNumOf_mountedSensors) als aller erste -// Abfrage machen ... noch bevor "SensorSlotOfAgent* sensorSlotOfAgent = new -// SensorSlotOfAgent();" -// TODO: delete object if it cannot added to vector -bool SensorHandlerOfAgent::mount_sensorIntoSensorSlot(Channel *inputPort) { - SensorSlotOfAgent *sensorSlotOfAgent = new SensorSlotOfAgent(); - if (sensorSlotOfAgent != NULL) { - if (sensorSlotOfAgent->set_comPort(inputPort)) { - try { - if (vMountedSensors.size() < maxNumOf_mountedSensors) { - vMountedSensors.push_back(sensorSlotOfAgent); - } else { - printError("Max number of mounted sensors is already reached!"); - - return false; - } - } catch (bad_alloc &error) { - printError("bad_alloc caught: ", error.what()); - return false; - } - return true; - } else { - printError("Input port is no set!"); - vMountedSensors.pop_back(); // TODO: check if it is right?!?! - - return false; - } - } else { - printError("Couldn't create SensorSlot!"); - - return false; - } -} - -// TODO: what to do when 2 sensorSlots have the same inputPort??!! -SensorSlotOfAgent * -SensorHandlerOfAgent::get_sensorSlotAddress(Channel *inputPort) { - for (auto &sensorSlot : vMountedSensors) { - if (sensorSlot->get_comPort() == inputPort) { - return sensorSlot; - } - } - return NULL; -} - -// TODO: what to do when 2 slaveAgentSlots have the same inputPort??!! -// TODO: case if slot with comPort is not in this vector -unsigned int SensorHandlerOfAgent::get_sensorSlotNumber(Channel *inputPort) { - unsigned int slotNumber = 0; - for (auto &sensorSlot : vMountedSensors) { - if (sensorSlot->get_comPort() == inputPort) { - return slotNumber; - } - slotNumber++; - } - return 0; -} - -// TODO: what to do when 2 sensorSlots have the same historyModule??!! -SensorSlotOfAgent * -SensorHandlerOfAgent::get_sensorSlotAddress(HistoryModule *historyModule) { - for (auto &sensorSlot : vMountedSensors) { - if (sensorSlot->get_historyModule() == historyModule) { - return sensorSlot; - } - } - return NULL; -} - -// TODO: what to do when 2 sensorSlots have the same confidenceModule??!! -SensorSlotOfAgent *SensorHandlerOfAgent::get_sensorSlotAddress( - ConfidenceModule *confidenceModule) { - for (auto &sensorSlot : vMountedSensors) { - if (sensorSlot->get_confidenceModule() == confidenceModule) { - return sensorSlot; - } - } - return NULL; -} - -bool SensorHandlerOfAgent::demount_sensor(Channel *inputPort) { - vMountedSensors.erase(vMountedSensors.begin() + - get_sensorSlotNumber(inputPort)); - return false; -} - -// TODO: do it also for integer variables -bool SensorHandlerOfAgent::read_sensorValue( - SensorSlotOfAgent *sensorSlotOfAgent) { - if (sensorSlotOfAgent != NULL) { - Channel *channel = sensorSlotOfAgent->get_comPort(); - if (channel != NULL) { - float inputValue; - if (channel->get_MsgUp(&inputValue)) { - sensorSlotOfAgent->set_sensorValue(inputValue); - return true; - } - } - } - return false; -} - -bool SensorHandlerOfAgent::read_allSensorValues() { - bool flag_readSensor = false; - for (auto &sensorSlot : vMountedSensors) { - if (read_sensorValue(sensorSlot)) { - flag_readSensor = true; - } - } - return flag_readSensor; -} - -bool SensorHandlerOfAgent::attach_historyModule(Channel *inputPort, - HistoryModule *historyModule) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(inputPort); - if (sensorSlotOfAgent != NULL) { - return sensorSlotOfAgent->set_historyModule(historyModule); - } - return false; -} - -bool SensorHandlerOfAgent::detach_historyModule( - SensorSlotOfAgent *sensorSlotOfAgent) { - if (sensorSlotOfAgent != NULL) { - return sensorSlotOfAgent->del_historyModule(); - } - return false; -} - -bool SensorHandlerOfAgent::detach_historyModule(Channel *inputPort) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(inputPort); - return detach_historyModule(sensorSlotOfAgent); -} - -bool SensorHandlerOfAgent::detach_historyModule(HistoryModule *historyModule) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(historyModule); - return detach_historyModule(sensorSlotOfAgent); -} - -HistoryModule * -SensorHandlerOfAgent::get_historyModuleOfSensorSlot(Channel *inputPort) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(inputPort); - return sensorSlotOfAgent->get_historyModule(); -} - -bool SensorHandlerOfAgent::attach_confidenceModule( - Channel *inputPort, ConfidenceModule *confidenceModule) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(inputPort); - if (sensorSlotOfAgent != NULL) { - return sensorSlotOfAgent->set_confidenceModule(confidenceModule); - } - return false; -} - -bool SensorHandlerOfAgent::detach_confidenceModule( - SensorSlotOfAgent *sensorSlotOfAgent) { - if (sensorSlotOfAgent != NULL) { - return sensorSlotOfAgent->del_confidenceModule(); - } - return false; -} - -bool SensorHandlerOfAgent::detach_confidenceModule(Channel *inputPort) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(inputPort); - return detach_confidenceModule(sensorSlotOfAgent); -} - -bool SensorHandlerOfAgent::detach_confidenceModule( - ConfidenceModule *confidenceModule) { - SensorSlotOfAgent *sensorSlotOfAgent = - get_sensorSlotAddress(confidenceModule); - return detach_confidenceModule(sensorSlotOfAgent); -} - -ConfidenceModule * -SensorHandlerOfAgent::get_confidenceModuleOfSensorSlot(Channel *inputPort) { - SensorSlotOfAgent *sensorSlotOfAgent = get_sensorSlotAddress(inputPort); - return sensorSlotOfAgent->get_confidenceModule(); -} - -vector *SensorHandlerOfAgent::get_vMountedSensors() { - return &vMountedSensors; -} diff --git a/lib/gen_agent_test2/SensorHandlerOfAgent.h b/lib/gen_agent_test2/SensorHandlerOfAgent.h deleted file mode 100644 index b216c65..0000000 --- a/lib/gen_agent_test2/SensorHandlerOfAgent.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SENSORHANDLEROFAGENT_HEADERFILE -#define SENSORHANDLEROFAGENT_HEADERFILE - -#include "SensorSlotOfAgent.h" -#include "Unit.h" -#include - -using namespace std; - -class SensorHandlerOfAgent : public Unit { - -private: - // TODO: set- and get function for maxNumOf_mountedSensors; - vector vMountedSensors; - unsigned int maxNumOf_mountedSensors; - - void init_sensorHandler(); - -public: - SensorHandlerOfAgent(); - - bool mount_sensorIntoSensorSlot(Channel *inputPort); - SensorSlotOfAgent *get_sensorSlotAddress(Channel *inputPort); - unsigned int get_sensorSlotNumber(Channel *inputPort); - SensorSlotOfAgent *get_sensorSlotAddress(HistoryModule *history); - SensorSlotOfAgent *get_sensorSlotAddress(ConfidenceModule *confidenceModule); - bool demount_sensor(Channel *inputPort); - - bool read_sensorValue(SensorSlotOfAgent *sensorSlot); - bool read_allSensorValues(); - - bool attach_historyModule(Channel *inputPort, HistoryModule *historyModule); - bool detach_historyModule(SensorSlotOfAgent *sensorSlotOfAgent); - bool detach_historyModule(Channel *inputPort); - bool detach_historyModule(HistoryModule *historyModule); - HistoryModule *get_historyModuleOfSensorSlot(Channel *inputPort); - - bool attach_confidenceModule(Channel *inputPort, - ConfidenceModule *confidenceModule); - bool detach_confidenceModule(SensorSlotOfAgent *sensorSlotOfAgent); - bool detach_confidenceModule(Channel *inputPort); - bool detach_confidenceModule(ConfidenceModule *confidenceModule); - ConfidenceModule *get_confidenceModuleOfSensorSlot(Channel *inputPort); - - vector *get_vMountedSensors(); -}; - -#endif diff --git a/lib/gen_agent_test2/SensorSlotOfAgent.cpp b/lib/gen_agent_test2/SensorSlotOfAgent.cpp deleted file mode 100644 index d54645d..0000000 --- a/lib/gen_agent_test2/SensorSlotOfAgent.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "SensorSlotOfAgent.h" -#include - -SensorSlotOfAgent::SensorSlotOfAgent() { - flagSensorValueIsSet = false; - flagSensorValueHasChanged = false; -} - -void SensorSlotOfAgent::set_sensorValue(float sensorValue) { - if (flagSensorValueIsSet == false) { - this->sensorValue = sensorValue; - flagSensorValueHasChanged = true; - flagSensorValueIsSet = true; - } else { - if (this->sensorValue != sensorValue) { - this->sensorValue = sensorValue; - flagSensorValueHasChanged = true; - } else { - flagSensorValueHasChanged = false; - } - } - - printf("sensorSlot updated with: %f\n", this->sensorValue); -} - -bool SensorSlotOfAgent::get_sensorValue(float *sensorValue) { - if (flagSensorValueIsSet == true) { - *sensorValue = this->sensorValue; - return true; - } - return false; -} - -bool SensorSlotOfAgent::get_flagSensorValueIsSet() { - return flagSensorValueIsSet; -} - -bool SensorSlotOfAgent::get_flagSensorValueHasChanged() { - return flagSensorValueHasChanged; -} - diff --git a/lib/gen_agent_test2/SensorSlotOfAgent.h b/lib/gen_agent_test2/SensorSlotOfAgent.h deleted file mode 100644 index 000116f..0000000 --- a/lib/gen_agent_test2/SensorSlotOfAgent.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SENSORSLOT_HEADERFILE -#define SENSORSLOT_HEADERFILE - -#include "SlotOfAgent.h" - -// TODO: set name of slot as the name of the sensor is (+ "slot"); -class SensorSlotOfAgent : public SlotOfAgent { - -private: - float sensorValue; - bool flagSensorValueIsSet; - bool flagSensorValueHasChanged; - -public: - SensorSlotOfAgent(); - - void set_sensorValue(float sensorValue); - bool get_sensorValue(float *sensorValue); - - bool get_flagSensorValueIsSet(); - bool get_flagSensorValueHasChanged(); -}; - -#endif diff --git a/lib/gen_agent_test2/SensorSlotOfTestbench.cpp b/lib/gen_agent_test2/SensorSlotOfTestbench.cpp deleted file mode 100644 index 61cb65b..0000000 --- a/lib/gen_agent_test2/SensorSlotOfTestbench.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "SensorSlotOfTestbench.h" - -void SensorSlotOfTestbench::init_sensorSlotOfTestbench() { - sensor = NULL; - csvReaderModule = NULL; -} - -SensorSlotOfTestbench::SensorSlotOfTestbench() { init_sensorSlotOfTestbench(); } - -bool SensorSlotOfTestbench::set_sensor(Sensor *sensor) { - if (sensor != NULL) { - this->sensor = sensor; - return true; - } - return false; -} - -bool SensorSlotOfTestbench::del_sensor() { - if (sensor != NULL) { - sensor = NULL; - return true; - } - return false; -} - -Sensor *SensorSlotOfTestbench::get_sensor() { return sensor; } - -bool SensorSlotOfTestbench::set_csvReaderModule( - CSVreaderModule *csvReaderModule) { - if (csvReaderModule != NULL) { - this->csvReaderModule = csvReaderModule; - return true; - } - return false; -} - -bool SensorSlotOfTestbench::del_csvReaderModule() { - if (csvReaderModule != NULL) { - csvReaderModule = NULL; - return true; - } - return false; -} - -CSVreaderModule *SensorSlotOfTestbench::get_csvReaderModule() { - return csvReaderModule; -} - diff --git a/lib/gen_agent_test2/SensorSlotOfTestbench.h b/lib/gen_agent_test2/SensorSlotOfTestbench.h deleted file mode 100644 index 55dcadc..0000000 --- a/lib/gen_agent_test2/SensorSlotOfTestbench.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SENSORSLOTOFTESTBENCH_HEADERFILE -#define SENSORSLOTOFTESTBENCH_HEADERFILE - -#include "CSVreaderModule.h" -#include "Sensor.h" - -class SensorSlotOfTestbench { - -protected: - Sensor *sensor; - CSVreaderModule *csvReaderModule; - - void init_sensorSlotOfTestbench(); - -public: - SensorSlotOfTestbench(); - - bool set_sensor(Sensor *sensor); - bool del_sensor(); - Sensor *get_sensor(); - - bool set_csvReaderModule(CSVreaderModule *csvReaderModule); - bool del_csvReaderModule(); - CSVreaderModule *get_csvReaderModule(); -}; - -#endif diff --git a/lib/gen_agent_test2/SlaveAgentHandlerOfAgent.cpp b/lib/gen_agent_test2/SlaveAgentHandlerOfAgent.cpp deleted file mode 100644 index f12e7c9..0000000 --- a/lib/gen_agent_test2/SlaveAgentHandlerOfAgent.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "SlaveAgentHandlerOfAgent.h" - -#include "instruction_set_architecture.h" -#include "printError.h" -#include - -#include - -#define MAXNUMOF_MOUNTEDSENSORS 100 - -using namespace std; - -SlaveAgentHandlerOfAgent::SlaveAgentHandlerOfAgent() { - initSlaveAgentHandler(); -} - -void SlaveAgentHandlerOfAgent::initSlaveAgentHandler() { - maxNumOfMountedSlaveAgents = MAXNUMOF_MOUNTEDSENSORS; -} - -bool SlaveAgentHandlerOfAgent::mount_slaveAgentIntoSlaveAgentSlot( - Channel *inputPort) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = new SlaveAgentSlotOfAgent(); - if (slaveAgentSlotOfAgent != NULL) { - if (slaveAgentSlotOfAgent->set_comPort(inputPort)) { - if (vMountedSlaveAgents.size() < maxNumOfMountedSlaveAgents) { - try { - vMountedSlaveAgents.push_back(slaveAgentSlotOfAgent); - } catch (bad_alloc &error) { - printError("bad_alloc caught: ", error.what()); - delete slaveAgentSlotOfAgent; - return false; - } - } else { - printError("Max number of mounted slaveAgents is already reached!"); - delete slaveAgentSlotOfAgent; - return false; - } - return true; - } else { - printError("Input port is no set!"); - vMountedSlaveAgents.pop_back(); // TODO: check if it is right?!?! - delete slaveAgentSlotOfAgent; - return false; - } - } else { - printError("Couldn't create SlaveAgentSlot!"); - return false; - } -} - -// TODO: what to do when 2 slaveAgentSlots have the same inputPort??!! -SlaveAgentSlotOfAgent * -SlaveAgentHandlerOfAgent::get_slaveAgentSlotAddress(Channel *inputPort) { - for (auto &slaveAgentSlot : vMountedSlaveAgents) { - if (slaveAgentSlot->get_comPort() == inputPort) { - return slaveAgentSlot; - } - } - return NULL; -} - -// TODO: what to do when 2 slaveAgentSlots have the same inputPort??!! -// TODO: case if slot with comPort is not in this vector -unsigned int -SlaveAgentHandlerOfAgent::get_slaveAgentSlotNumber(Channel *inputPort) { - unsigned int slotNumber = 0; - for (auto &slaveAgentSlot : vMountedSlaveAgents) { - if (slaveAgentSlot->get_comPort() == inputPort) { - return slotNumber; - } - slotNumber++; - } - return 0; -} - -// TODO: what to do when 2 slaveAgentSlots have the same historyModule??!! -SlaveAgentSlotOfAgent *SlaveAgentHandlerOfAgent::get_slaveAgentSlotAddress( - HistoryModule *historyModule) { - for (auto &slaveAgentSlot : vMountedSlaveAgents) { - if (slaveAgentSlot->get_historyModule() == historyModule) { - return slaveAgentSlot; - } - } - return NULL; -} - -// TODO: what to do when 2 slaveAgentSlots have the same confidenceModule??!! -SlaveAgentSlotOfAgent *SlaveAgentHandlerOfAgent::get_slaveAgentSlotAddress( - ConfidenceModule *confidenceModule) { - for (auto &slaveAgentSlot : vMountedSlaveAgents) { - if (slaveAgentSlot->get_confidenceModule() == confidenceModule) { - return slaveAgentSlot; - } - } - return NULL; -} - -bool SlaveAgentHandlerOfAgent::demount_slaveAgentIntoSlaveAgentSlot( - Channel *inputPort) { - vMountedSlaveAgents.erase(vMountedSlaveAgents.begin() + - get_slaveAgentSlotNumber(inputPort)); - return false; -} - -// TODO: do it also for integer variables -bool SlaveAgentHandlerOfAgent::read_slaveAgentValue( - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent) { - if (slaveAgentSlotOfAgent != NULL) { - Channel *channel = slaveAgentSlotOfAgent->get_comPort(); - if (channel != NULL) { - int msg; - if (channel->get_MsgUp(&msg)) { - if (msg == ISA_SensoryData) { - printf("got msg: \n"); - float inputValue; - if (channel->get_MsgUp(&inputValue)) { - slaveAgentSlotOfAgent->set_slaveAgentValue(inputValue); - return true; - } - } - } - } - } - return false; -} - -bool SlaveAgentHandlerOfAgent::read_allSlaveAgentValues() { - bool flag_readSlaveAgent = false; - for (auto &slaveAgentSlot : vMountedSlaveAgents) { - if (read_slaveAgentValue(slaveAgentSlot)) { - flag_readSlaveAgent = true; - } - } - return flag_readSlaveAgent; -} - -bool SlaveAgentHandlerOfAgent::attach_historyModule( - Channel *inputPort, HistoryModule *historyModule) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(inputPort); - if (slaveAgentSlotOfAgent != NULL) { - return slaveAgentSlotOfAgent->set_historyModule(historyModule); - } - return false; -} - -bool SlaveAgentHandlerOfAgent::detach_historyModule( - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent) { - if (slaveAgentSlotOfAgent != NULL) { - return slaveAgentSlotOfAgent->del_historyModule(); - } - return false; -} - -bool SlaveAgentHandlerOfAgent::detach_historyModule(Channel *inputPort) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(inputPort); - return detach_historyModule(slaveAgentSlotOfAgent); -} - -bool SlaveAgentHandlerOfAgent::detach_historyModule( - HistoryModule *historyModule) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(historyModule); - return detach_historyModule(slaveAgentSlotOfAgent); -} - -HistoryModule *SlaveAgentHandlerOfAgent::get_historyModuleOfSlaveAgentSlot( - Channel *inputPort) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(inputPort); - return slaveAgentSlotOfAgent->get_historyModule(); -} - -bool SlaveAgentHandlerOfAgent::attach_confidenceModule( - Channel *inputPort, ConfidenceModule *confidenceModule) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(inputPort); - if (slaveAgentSlotOfAgent != NULL) { - return slaveAgentSlotOfAgent->set_confidenceModule(confidenceModule); - } - return false; -} - -bool SlaveAgentHandlerOfAgent::detach_confidenceModule( - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent) { - if (slaveAgentSlotOfAgent != NULL) { - return slaveAgentSlotOfAgent->del_confidenceModule(); - } - return false; -} - -bool SlaveAgentHandlerOfAgent::detach_confidenceModule(Channel *inputPort) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(inputPort); - return detach_confidenceModule(slaveAgentSlotOfAgent); -} - -bool SlaveAgentHandlerOfAgent::detach_confidenceModule( - ConfidenceModule *confidenceModule) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(confidenceModule); - return detach_confidenceModule(slaveAgentSlotOfAgent); -} - -ConfidenceModule * -SlaveAgentHandlerOfAgent::get_confidenceModuleOfSlaveAgentSlot( - Channel *inputPort) { - SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent = - get_slaveAgentSlotAddress(inputPort); - return slaveAgentSlotOfAgent->get_confidenceModule(); -} - -vector * -SlaveAgentHandlerOfAgent::get_vMountedSlaveAgents() { - return &vMountedSlaveAgents; -} diff --git a/lib/gen_agent_test2/SlaveAgentHandlerOfAgent.h b/lib/gen_agent_test2/SlaveAgentHandlerOfAgent.h deleted file mode 100644 index 2b40761..0000000 --- a/lib/gen_agent_test2/SlaveAgentHandlerOfAgent.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef SLAVEAGENTHANDLEROFAGENT_HEADERFILE -#define SLAVEAGENTHANDLEROFAGENT_HEADERFILE - -#include "SlaveAgentSlotOfAgent.h" -#include "Unit.h" -#include - -using namespace std; - -class SlaveAgentHandlerOfAgent : public Unit { - -private: - // TODO: set- and get function for maxNumOf_mountedSlaveAgents; - vector vMountedSlaveAgents; - unsigned int maxNumOfMountedSlaveAgents; - - void initSlaveAgentHandler(); - -public: - SlaveAgentHandlerOfAgent(); - - bool mount_slaveAgentIntoSlaveAgentSlot(Channel *inputPort); - SlaveAgentSlotOfAgent *get_slaveAgentSlotAddress(Channel *inputPort); - unsigned int get_slaveAgentSlotNumber(Channel *inputPort); - SlaveAgentSlotOfAgent *get_slaveAgentSlotAddress(HistoryModule *history); - SlaveAgentSlotOfAgent * - get_slaveAgentSlotAddress(ConfidenceModule *confidenceModule); - bool demount_slaveAgentIntoSlaveAgentSlot(Channel *inputPort); - - bool read_slaveAgentValue(SlaveAgentSlotOfAgent *slaveAgentSlot); - bool read_allSlaveAgentValues(); - - bool attach_historyModule(Channel *inputPort, HistoryModule *historyModule); - bool detach_historyModule(SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent); - bool detach_historyModule(Channel *inputPort); - bool detach_historyModule(HistoryModule *historyModule); - HistoryModule *get_historyModuleOfSlaveAgentSlot(Channel *inputPort); - - bool attach_confidenceModule(Channel *inputPort, - ConfidenceModule *confidenceModule); - bool detach_confidenceModule(SlaveAgentSlotOfAgent *slaveAgentSlotOfAgent); - bool detach_confidenceModule(Channel *inputPort); - bool detach_confidenceModule(ConfidenceModule *confidenceModule); - ConfidenceModule *get_confidenceModuleOfSlaveAgentSlot(Channel *inputPort); - - vector *get_vMountedSlaveAgents(); -}; - -#endif diff --git a/lib/gen_agent_test2/SlaveAgentSlotOfAgent.cpp b/lib/gen_agent_test2/SlaveAgentSlotOfAgent.cpp deleted file mode 100644 index e0c019b..0000000 --- a/lib/gen_agent_test2/SlaveAgentSlotOfAgent.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "SlaveAgentSlotOfAgent.h" -#include - -SlaveAgentSlotOfAgent::SlaveAgentSlotOfAgent() { - flag_slaveAgentValueIsSet = false; - flag_slaveAgentValueHasChanged = false; -} - -void SlaveAgentSlotOfAgent::set_slaveAgentValue(float slaveAgentValue) { - if (flag_slaveAgentValueIsSet == false) { - this->slaveAgentValue = slaveAgentValue; - flag_slaveAgentValueHasChanged = true; - flag_slaveAgentValueIsSet = true; - } else { - if (this->slaveAgentValue != slaveAgentValue) { - this->slaveAgentValue = slaveAgentValue; - flag_slaveAgentValueHasChanged = true; - } else { - flag_slaveAgentValueHasChanged = false; - } - } - printf("slaveAgentSlot updated with: %f\n", this->slaveAgentValue); -} - -bool SlaveAgentSlotOfAgent::get_slaveAgentValue(float *slaveAgentValue) { - if (flag_slaveAgentValueIsSet == true) { - *slaveAgentValue = this->slaveAgentValue; - return true; - } - return false; -} diff --git a/lib/gen_agent_test2/SlaveAgentSlotOfAgent.h b/lib/gen_agent_test2/SlaveAgentSlotOfAgent.h deleted file mode 100644 index 4274a36..0000000 --- a/lib/gen_agent_test2/SlaveAgentSlotOfAgent.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SLAVEAGENTSLOTOFAGENT_HEADERFILE -#define SLAVEAGENTSLOTOFAGENT_HEADERFILE - -#include "SlotOfAgent.h" - -class SlaveAgentSlotOfAgent : public SlotOfAgent { - -private: - // TODO: set- and get function for maxNumOf_mountedSensors; - float slaveAgentValue; - bool flag_slaveAgentValueIsSet; - bool flag_slaveAgentValueHasChanged; - -public: - SlaveAgentSlotOfAgent(); - - void set_slaveAgentValue(float slaveAgentValue); - bool get_slaveAgentValue(float *slaveAgentValue); -}; - -#endif diff --git a/lib/gen_agent_test2/Slot.cpp b/lib/gen_agent_test2/Slot.cpp deleted file mode 100644 index b48893c..0000000 --- a/lib/gen_agent_test2/Slot.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Slot.h" - -#include - -Slot::Slot() {} - -bool Slot::set_comPort(Channel *comPort) { - if (comPort != NULL) { - this->comPort = comPort; - return true; - } - return false; -} - -Channel *Slot::get_comPort() { return comPort; } diff --git a/lib/gen_agent_test2/Slot.h b/lib/gen_agent_test2/Slot.h deleted file mode 100644 index 21b659d..0000000 --- a/lib/gen_agent_test2/Slot.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SLOT_HEADERFILE -#define SLOT_HEADERFILE - -#include "Channel.h" - -class Slot : public Unit { - -protected: - Channel *comPort; - -public: - Slot(); - - bool set_comPort(Channel *comPort); - Channel *get_comPort(); -}; - -#endif diff --git a/lib/gen_agent_test2/SlotOfAgent.cpp b/lib/gen_agent_test2/SlotOfAgent.cpp deleted file mode 100644 index 6776535..0000000 --- a/lib/gen_agent_test2/SlotOfAgent.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "SlotOfAgent.h" - -#include - -SlotOfAgent::SlotOfAgent() {} - -bool SlotOfAgent::set_historyModule(HistoryModule *historyModule) { - if (historyModule != NULL) { - this->historyModule = historyModule; - return true; - } - return false; -} - -bool SlotOfAgent::del_historyModule() { - if (historyModule != NULL) { - historyModule = NULL; - return true; - } - return false; -} - -HistoryModule *SlotOfAgent::get_historyModule() { return historyModule; } - -bool SlotOfAgent::set_confidenceModule(ConfidenceModule *confidenceModule) { - if (confidenceModule != NULL) { - this->confidenceModule = confidenceModule; - return true; - } - return false; -} - -bool SlotOfAgent::del_confidenceModule() { - if (confidenceModule != NULL) { - confidenceModule = NULL; - return true; - } - return false; -} - -ConfidenceModule *SlotOfAgent::get_confidenceModule() { - return confidenceModule; -} diff --git a/lib/gen_agent_test2/SlotOfAgent.h b/lib/gen_agent_test2/SlotOfAgent.h deleted file mode 100644 index 337210d..0000000 --- a/lib/gen_agent_test2/SlotOfAgent.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SLOTOFAGENT_HEADERFILE -#define SLOTOFAGENT_HEADERFILE - -#include "ConfidenceModule.h" -#include "HistoryModule.h" -#include "Slot.h" - -class SlotOfAgent : public Slot { - -protected: - HistoryModule *historyModule; - ConfidenceModule *confidenceModule; - // Abstraction - -public: - SlotOfAgent(); - - bool set_historyModule(HistoryModule *historyModule); - bool del_historyModule(); - HistoryModule *get_historyModule(); - - bool set_confidenceModule(ConfidenceModule *confidenceModule); - bool del_confidenceModule(); - ConfidenceModule *get_confidenceModule(); -}; - -#endif diff --git a/lib/gen_agent_test2/Testbench.cpp b/lib/gen_agent_test2/Testbench.cpp deleted file mode 100644 index aace67f..0000000 --- a/lib/gen_agent_test2/Testbench.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "Testbench.h" - -#include "printError.h" -#include - -#define MAXNUMOF_REGISTEREDCAGENTS 1000 -#define MAXNUMOF_REGISTEREDCHANNELS 1000 -#define MAXNUMOF_REGISTEREDSENSORS 1000 - -using namespace std; - -void Testbench::init_testbench() { - maxNumOf_registeredAgents = MAXNUMOF_REGISTEREDCAGENTS; - maxNumOf_registeredChannels = MAXNUMOF_REGISTEREDCHANNELS; - maxNumOf_registeredSensors = MAXNUMOF_REGISTEREDSENSORS; -} - -Testbench::Testbench() { set_name(NO_NAME); } - -Testbench::Testbench(const char *name) { set_name(name); } - -bool Testbench::register_agent(Agent *agent) { - AgentSlotOfTestbench *agentSlot = new AgentSlotOfTestbench(); - if (agentSlot != NULL) { - if (agentSlot->set_agent(agent)) { - try { - if (vector_registeredAgents.size() < maxNumOf_registeredAgents) { - vector_registeredAgents.push_back(agentSlot); - } else { - printError("Max number of registered agents is already reached!"); - return false; - } - } catch (bad_alloc &error) { - printError("bad_alloc caught: ", error.what()); - return false; - } - return true; - } else { - printError("Agent is not set!"); - vector_registeredAgents.pop_back(); // TODO: check if it is right?!?! - return false; - } - } else { - printError("Couldn't create AgentSlot!"); - return false; - } -} - -bool Testbench::register_sensor(Sensor *sensor) { - SensorSlotOfTestbench *sensorSlot = new SensorSlotOfTestbench(); - if (sensorSlot != NULL) { - if (sensorSlot->set_sensor(sensor)) { - try { - if (vector_registeredSensors.size() < maxNumOf_registeredSensors) { - vector_registeredSensors.push_back(sensorSlot); - } else { - printError("Max number of registered sensors is already reached!"); - return false; - } - } catch (bad_alloc &error) { - printError("bad_alloc caught: ", error.what()); - return false; - } - return true; - } else { - printError("Input port is no set!"); - vector_registeredSensors.pop_back(); // TODO: check if it is right?!?! - return false; - } - } else { - printError("Couldn't create SensorSlot!"); - return false; - } -} - -SensorSlotOfTestbench * -Testbench::get_sensorSlotAddressOfTestbench(Sensor *sensor) { - for (auto &sensorSlot : vector_registeredSensors) { - if (sensorSlot->get_sensor() == sensor) { - return sensorSlot; - } - } - return NULL; -} - -bool Testbench::register_channel(Channel *channel) { - ChannelSlotOfTestbench *channelSlot = new ChannelSlotOfTestbench(); - if (channelSlot != NULL) { - if (channelSlot->set_channel(channel)) { - try { - if (vector_registeredChannels.size() < maxNumOf_registeredChannels) { - vector_registeredChannels.push_back(channelSlot); - } else { - printError("Max number of registered channels is already reached!"); - return false; - } - } catch (bad_alloc &error) { - printError("bad_alloc caught: ", error.what()); - return false; - } - return true; - } else { - printError("Channel is not set!"); - vector_registeredChannels.pop_back(); // TODO: check if it is right?!?! - return false; - } - } else { - printError("Couldn't create ChannelSlot!"); - return false; - } -} - -void Testbench::simulate(unsigned int rounds) { - for (unsigned int sec = 1; sec <= rounds; sec++) { - - printf("cycle %u\n", sec); - - // update sensor values - for (auto &sensorSlot : vector_registeredSensors) { - Sensor *sensor = sensorSlot->get_sensor(); - if (sensor != NULL) { - CSVreaderModule *csvReader = sensorSlot->get_csvReaderModule(); - if (csvReader != NULL) { - float inputValue; - if (csvReader->get_next_value(&inputValue)) { - sensor->set_sensorValue(inputValue); - } - } - } - } - - // trigger sensors - for (auto &sensorSlot : vector_registeredSensors) { - Sensor *sensor = sensorSlot->get_sensor(); - if (sensor != NULL) { - sensor->trigger(); - } - } - - // trigger channels - for (auto &channelSlot : vector_registeredChannels) { - Channel *channel = channelSlot->get_channel(); - if (channel != NULL) { - channel->trigger(); - } - } - - // trigger agents - for (auto &agentSlot : vector_registeredAgents) { - Agent *agent = agentSlot->get_agent(); - if (agent != NULL) { - agent->trigger(); - } - } - getchar(); - } -} - diff --git a/lib/gen_agent_test2/Testbench.h b/lib/gen_agent_test2/Testbench.h deleted file mode 100644 index 04ba1b5..0000000 --- a/lib/gen_agent_test2/Testbench.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef TESTBENCH_HEADERFILE -#define TESTBENCH_HEADERFILE - -#include "AgentSlotOfTestbench.h" -#include "CSVreaderModule.h" -#include "ChannelSlotOfTestbench.h" -#include "SensorSlotOfTestbench.h" -#include "Unit.h" -#include - -using namespace std; - -class Testbench : public Module { - -private: - // TODO: set- and get function for maxNumOf_registeredAgents; - vector vector_registeredAgents; - unsigned int maxNumOf_registeredAgents; - - // TODO: set- and get function for maxNumOf_registeredChannels; - vector vector_registeredChannels; - unsigned int maxNumOf_registeredChannels; - - // TODO: set- and get function for maxNumOf_registeredSensors; - vector vector_registeredSensors; - unsigned int maxNumOf_registeredSensors; - - void init_testbench(); - -public: - Testbench(); - Testbench(const char *name); - - bool register_agent(Agent *agent); - - bool register_sensor(Sensor *sensor); - SensorSlotOfTestbench *get_sensorSlotAddressOfTestbench(Sensor *sensor); - - bool register_channel(Channel *channel); - - void simulate(unsigned int rounds); -}; - -#endif diff --git a/lib/gen_agent_test2/Unit.cpp b/lib/gen_agent_test2/Unit.cpp deleted file mode 100644 index 4c9428c..0000000 --- a/lib/gen_agent_test2/Unit.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "Unit.h" - -unsigned int Unit::num_of_units = 0; - -Unit::Unit() { - this->id = num_of_units; - num_of_units++; -} - -void Unit::set_id(unsigned int id) { this->id = id; } - -unsigned int Unit::get_id() { return this->id; } diff --git a/lib/gen_agent_test2/Unit.h b/lib/gen_agent_test2/Unit.h deleted file mode 100644 index fc9e6a5..0000000 --- a/lib/gen_agent_test2/Unit.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef UNIT_HEADERFILE -#define UNIT_HEADERFILE - -#define MAX_LENGTH_NAME 50 -#define NO_NAME "unnamed" - -#define MAX_NUM_OF_MOUNTED_SLAVEAGENTS 10 -#define MAX_NUM_OF_MOUNTED_SENSORS 10 - -#define MAX_NUM_OF_DATA_SETS 100 - -#define MOUNTED true -#define UNMOUNTED false - -#define ACTIVE true -#define INACTIVE false - -#define YES true -#define NO false - -#define BOUND true -#define NO_BOUND false - -#define RATES_OF_CHANGE true -#define NO_RATES_OF_CHANGE false - -class Unit { - -protected: - static unsigned int num_of_units; - unsigned int id; - -public: - Unit(); - - void set_id(unsigned int value); - unsigned int get_id(); -}; - -#endif diff --git a/lib/gen_agent_test2/attach_modules.cpp b/lib/gen_agent_test2/attach_modules.cpp deleted file mode 100644 index 1ed3b4e..0000000 --- a/lib/gen_agent_test2/attach_modules.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "attach_modules.h" -#include -//#include "rlutil.h" - -// using namespace rlutil; - -bool attach_historyModuleToSensorSlotInAgent(Agent *agent, Sensor *sensor, - Channel *inputPort, - HistoryModule *historyModule) { - if (agent != NULL && inputPort != NULL && historyModule != NULL) { - SensorSlotOfAgent *sensorSlotOfAgent = - agent->get_sensorHandlerOfAgent()->get_sensorSlotAddress(inputPort); - if (sensorSlotOfAgent != NULL) { - printf(" > HistoryModule "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", historyModule->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", historyModule->get_id()); - if (sensorSlotOfAgent->set_historyModule(historyModule)) { - // setColor(TXTCOLOR_LIGHTGREEN); - printf("attached "); - // setColor(TXTCOLOR_GREY); - printf("to Sensor "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", sensor->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) in Agent ", sensor->get_id()); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", agent->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u)\n", agent->get_id()); - return true; - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("Couldn't attach the HistoryModule!\n"); - // setColor(TXTCOLOR_GREY); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Couldn't attach the HistoryModule because Sensor isn't " - "mounted in %s (id: %03u)!\n", - agent->get_name(), agent->get_id()); - // setColor(TXTCOLOR_GREY); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Couldn't attach the HistoryModule because Agent, Channel, or " - "HistoryModule is not valid!\n"); - // setColor(TXTCOLOR_GREY); - } - return false; -} diff --git a/lib/gen_agent_test2/attach_modules.h b/lib/gen_agent_test2/attach_modules.h deleted file mode 100644 index e5ce013..0000000 --- a/lib/gen_agent_test2/attach_modules.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef ATTACHMODULES_HEADERFILE -#define ATTACHMODULES_HEADERFILE - -#include "Agent.h" -#include "Sensor.h" - -bool attach_historyModuleToSensorSlotInAgent(Agent *agent, Sensor *sensor, - Channel *inputPort, - HistoryModule *historyModule); - -#endif diff --git a/lib/gen_agent_test2/attach_modulesToTestbench.cpp b/lib/gen_agent_test2/attach_modulesToTestbench.cpp deleted file mode 100644 index 12d0d23..0000000 --- a/lib/gen_agent_test2/attach_modulesToTestbench.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "attach_modulesToTestbench.h" - -//#include "rlutil.h" -#include "SensorSlotOfTestbench.h" - -// using namespace rlutil; - -bool attach_csvReaderModuleToSensorSlotInAgent( - Testbench *testbench, Sensor *sensor, CSVreaderModule *csvReaderModule) { - if (testbench != NULL && sensor != NULL && csvReaderModule != NULL) { - SensorSlotOfTestbench *sensorSlot = - testbench->get_sensorSlotAddressOfTestbench(sensor); - if (sensorSlot != NULL) { - printf(" > CSV-Reader "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", csvReaderModule->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", csvReaderModule->get_id()); - if (sensorSlot->set_csvReaderModule(csvReaderModule)) { - // setColor(TXTCOLOR_LIGHTGREEN); - printf("attached "); - // setColor(TXTCOLOR_GREY); - printf("to Sensor "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", sensor->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) in Testbench ", sensor->get_id()); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", testbench->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u)\n", testbench->get_id()); - return true; - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("Couldn't attach the CSVreaderModule!\n"); - // setColor(TXTCOLOR_GREY); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Couldn't attach the CSVreaderModule because Sensor isn't " - "registered in %s (id: %03u)!\n", - testbench->get_name(), testbench->get_id()); - // setColor(TXTCOLOR_GREY); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Couldn't attach the CSVreaderModule because Testbench, " - "Sensorm or CSVreaderModule is not valid!\n"); - // setColor(TXTCOLOR_GREY); - } - return false; -} diff --git a/lib/gen_agent_test2/attach_modulesToTestbench.h b/lib/gen_agent_test2/attach_modulesToTestbench.h deleted file mode 100644 index 036d935..0000000 --- a/lib/gen_agent_test2/attach_modulesToTestbench.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef ATTACHMODULESTOTESTBENCH_HEADERFILE -#define ATTACHMODULESTOTESTBENCH_HEADERFILE - -#include "CSVreaderModule.h" -#include "Sensor.h" -#include "Testbench.h" - -bool attach_csvReaderModuleToSensorSlotInAgent( - Testbench *testbench, Sensor *sensor, CSVreaderModule *csvReaderModule); - -#endif diff --git a/lib/gen_agent_test2/create_unit.cpp b/lib/gen_agent_test2/create_unit.cpp deleted file mode 100644 index 3bc5e67..0000000 --- a/lib/gen_agent_test2/create_unit.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "create_unit.h" -#include "rosa/config/config.h" -#include -//#include "rlutil.h" - -// using namespace rlutil; - -Agent create_agent() { return create_agent(NO_NAME); } - -Agent create_agent(const char *name) { - Agent agent(name); - - printf(" > Agent "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", agent.get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", agent.get_id()); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // setColor(TXTCOLOR_GREY); - - return agent; -} - -Sensor create_sensor() { return create_sensor(NO_NAME); } - -Sensor create_sensor(const char *name) { - Sensor sensor(name); - - printf(" > Sensor "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", sensor.get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", sensor.get_id()); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // setColor(TXTCOLOR_GREY); - - return sensor; -} - -HistoryModule create_historyModule(unsigned int history_length, - int delimitation_mode) { - return create_historyModule(NO_NAME, history_length, delimitation_mode); -} - -HistoryModule create_historyModule(const char *name, - unsigned int history_length, - int delimitation_mode) { - - HistoryModule historyModule(name); - - printf(" > History "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", historyModule.get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", historyModule.get_id()); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // setColor(TXTCOLOR_GREY); - if (historyModule.set_maxHistoryLength(history_length)) { - printf(" > History length "); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("set "); - // setColor(TXTCOLOR_GREY); - printf("to %u\n", history_length); - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > historyLength could not set (out of allowed range)."); - // setColor(TXTCOLOR_GREY); - } - if (historyModule.set_delimitationMode(delimitation_mode)) { - printf(" > Delimitation Mode "); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("set "); - // setColor(TXTCOLOR_GREY); - printf("to %u\n", delimitation_mode); - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Delimitation Mode could not set (out of allowed range)."); - // setColor(TXTCOLOR_GREY); - } - - return historyModule; -} - -Channel create_channel(unsigned int transfer_rate) { - return create_channel(NO_NAME, transfer_rate); -} - -Channel create_channel(const char *name, unsigned int transfer_rate) { - - Channel channel(name); - - printf(" > Channel "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", channel.get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", channel.get_id()); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // setColor(TXTCOLOR_GREY); - - if (channel.set_transferRate(transfer_rate)) { - if (transfer_rate != 0) { - printf(" > transfer rate "); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("set "); - // setColor(TXTCOLOR_GREY); - printf("to %i\n", transfer_rate); - } else { - printf(" > transfer "); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("set "); - // setColor(TXTCOLOR_GREY); - printf("to immediately transportation\n" /*, transfer_rate*/); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Transfer Rate out of allowed bounds!\n"); - // setColor(TXTCOLOR_GREY); - } - - return channel; -} - -Testbench create_testbench() { - Testbench testbench; - printf(" > "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", testbench.get_name()); - // rlutil::setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", testbench.get_id()); - // rlutil::setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // rlutil::setColor(TXTCOLOR_GREY); - return testbench; -} - -Testbench create_testbench(const char *name) { - Testbench testbench(name); - printf(" > "); - // rlutil::setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", testbench.get_name()); - // rlutil::setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", testbench.get_id()); - // rlutil::setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // rlutil::setColor(TXTCOLOR_GREY); - return testbench; -} - -FILE *make_file_pointer(const char *filepath, int mode) { - - FILE *fpointer; - // bool file_opened; - - if (mode == CSV_MODE_READ) { -#ifdef ROSA_WINDOWS - fopen_s(&fpointer, filepath, "r"); -#else - fpointer = fopen(filepath, "r"); -#endif - // file_opened = fopen_s(&fpointer, filepath, "r"); - } else if (mode == CSV_MODE_WRITE) { -#ifdef ROSA_WINDOWS - fopen_s(&fpointer, filepath, "r"); -#else - fpointer = fopen(filepath, "r"); -#endif - // file_opened = fopen_s(&fpointer, filepath, "w"); - } else { - printf("File pointer mode for \"%s\" ", filepath); - // rlutil::setColor(TXTCOLOR_LIGHTRED); - printf("is not supported!\n"); - // rlutil::setColor(TXTCOLOR_GREY); - - return NULL; - } - - if (fpointer /*file_opened == 0*/) { - return fpointer; - } - - printf("File pointer \"%s\" ", filepath); - // rlutil::setColor(TXTCOLOR_LIGHTRED); - printf("could not created!\n"); - // rlutil::setColor(TXTCOLOR_GREY); - - return NULL; -} - -void print_csv_reader(CSVreaderModule csvReaderModule, const char *filepath) { - printf(" > "); - // rlutil::setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", csvReaderModule.get_name()); - // rlutil::setColor(TXTCOLOR_GREY); - printf("(id: %03u) for \"%s\" ", csvReaderModule.get_id(), filepath); - // rlutil::setColor(TXTCOLOR_LIGHTGREEN); - printf("created\n"); - // rlutil::setColor(TXTCOLOR_GREY); -} - -CSVreaderModule create_CSVreaderModule(const char *filepath, - unsigned int column, - unsigned int start_row) { - - FILE *fpointer = make_file_pointer(filepath, CSV_MODE_READ); - - if (fpointer) { - CSVreaderModule csvr(fpointer, column, start_row); - print_csv_reader(csvr, filepath); - - return csvr; - } else { - CSVreaderModule csvr; - - return csvr; - } -} - -CSVreaderModule create_CSVreaderModule(const char *name, const char *filepath, - unsigned int column, - unsigned int start_row) { - - FILE *fpointer = make_file_pointer(filepath, CSV_MODE_READ); - - if (fpointer) { - CSVreaderModule csvr(name, fpointer, column, start_row); - print_csv_reader(csvr, filepath); - - return csvr; - } else { - CSVreaderModule csvr; - - return csvr; - } -} diff --git a/lib/gen_agent_test2/create_unit.h b/lib/gen_agent_test2/create_unit.h deleted file mode 100644 index 11ee903..0000000 --- a/lib/gen_agent_test2/create_unit.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CREATE_UNIT_HEADERFILE -#define CREATE_UNIT_HEADERFILE - -#include "Agent.h" -#include "CSVreaderModule.h" -#include "HistoryModule.h" -#include "Sensor.h" -#include "Testbench.h" - -#define CSV_MODE_READ 0 -#define CSV_MODE_WRITE 1 - -Agent create_agent(); -Agent create_agent(const char *name); - -Sensor create_sensor(); -Sensor create_sensor(const char *name); - -HistoryModule create_historyModule(unsigned int history_length, - int delimitation_mode); -HistoryModule create_historyModule(const char *name, - unsigned int history_length, - int delimitation_mode); - -Channel create_channel(unsigned int transfer_rate); -Channel create_channel(const char *name, unsigned int transfer_rate); - -Testbench create_testbench(); -Testbench create_testbench(const char *name); - -CSVreaderModule create_CSVreaderModule(const char *filepath, - unsigned int column, - unsigned int start_row); -CSVreaderModule create_CSVreaderModule(const char *name, const char *filepath, - unsigned int column, - unsigned int start_row); - -#endif diff --git a/lib/gen_agent_test2/instruction_set_architecture.h b/lib/gen_agent_test2/instruction_set_architecture.h deleted file mode 100644 index 3076d8c..0000000 --- a/lib/gen_agent_test2/instruction_set_architecture.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef INSTRUCTION_SET_HEADERFILE -#define INSTRUCTION_SET_HEADERFILE - -#define ISA_NoInstruction 0x0000 - -#define ISA_SensoryData 0x0100 -#define ISA_SensoryData_SendersID 0x0101 -#define ISA_SensoryData_ReiceiversID 0x0102 -#define ISA_SensoryData_SendersID_ReiceiversID 0x0103 -#define ISA_SensoryData_BinaryConfidenceTag 0x0104 - -#define ISA_SlaveAgentData 0x0200 -#define ISA_SlaveAgentWithBinaryConfidenceTag 0x0201 - -#endif diff --git a/lib/gen_agent_test2/main.cpp b/lib/gen_agent_test2/main.cpp deleted file mode 100644 index 70b8d94..0000000 --- a/lib/gen_agent_test2/main.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "Agent.h" -#include "CSVreaderModule.h" -#include "Channel.h" -#include "Sensor.h" -#include "Testbench.h" -#include "create_unit.h" -#include "mount_nodes.h" -#include "register_in_testbench.h" -#include - -int main(int argc, char *argv[]) { - (void)argc, (void)argv; - // create agents - printf("Create Agents\n"); - Agent a_statorVoltage = create_agent("StatorVoltage"); - Agent a_statorCurrent = create_agent("StatorCurrent"); - Agent a_speed = create_agent("Speed"); - Agent a_electromagneticTorque = create_agent("ElectromagneticTorque"); - Agent a_mechanicalTorque = create_agent("MechanicalTorque"); - Agent a_viabilityMonitor = create_agent("ViabilityMonitor"); - - // create sensors - printf("\nCreate Sensors\n"); - Sensor s_statorVoltage = create_sensor("Stator Voltage"); - Sensor s_statorCurrent = create_sensor("Stator Current"); - Sensor s_speed = create_sensor("Speed"); - Sensor s_electromagneticTorque = create_sensor("Electromagnetic Torque"); - Sensor s_mechanicalTorque = create_sensor("Mechanical Torque"); - - // create channels for sensors - printf("\nCreate Channels for Sensors\n"); - Channel c_sa_statorVoltage = create_channel("Stator Voltage (SA)", 0); - Channel c_sa_statorCurrent = create_channel("Stator Current (SA)", 0); - Channel c_sa_speed = create_channel("Speed Sensor (SA)", 0); - Channel c_sa_electromagneticTorque = - create_channel("Electromagnetic Torque (SA)", 0); - Channel c_sa_mechanicalTorque = create_channel("Mechanical Torque (SA)", 0); - - // create channels for sensors - printf("\nCreate Channels for Agents\n"); - Channel c_aa_statorVoltage = - create_channel("Stator Voltage (AA-UP)", MAX_BUFFER_LENGTH); - Channel c_aa_statorCurrent = - create_channel("Stator Current (AA-UP)", MAX_BUFFER_LENGTH); - Channel c_aa_speed = - create_channel("Speed Sensor (AA-UP)", MAX_BUFFER_LENGTH); - Channel c_aa_electromagneticTorque = - create_channel("Electromagnetic Torque (AA-UP)", MAX_BUFFER_LENGTH); - Channel c_aa_mechanicalTorque = - create_channel("Mechanical Torque (AA-UP)", MAX_BUFFER_LENGTH); - - // mount sensors in agents - printf("\nMount Sensors in Agents\n"); - mount_sensorInAgent(&a_statorVoltage, &s_statorVoltage, - &c_sa_statorVoltage); //, &hm_s_statorVoltage); - mount_sensorInAgent(&a_statorCurrent, &s_statorCurrent, - &c_sa_statorCurrent); //, &hm_s_statorCurrent); - mount_sensorInAgent(&a_speed, &s_speed, &c_sa_speed); //, &hm_s_speed); - mount_sensorInAgent( - &a_electromagneticTorque, &s_electromagneticTorque, - &c_sa_electromagneticTorque); //, &hm_s_electromagneticTorque); - mount_sensorInAgent(&a_mechanicalTorque, &s_mechanicalTorque, - &c_sa_mechanicalTorque); //, &hm_s_mechanicalTorque); - - // mount agents in agent(s) - printf("\nMount Agents in Agents\n"); - mount_agentInAgent(&a_viabilityMonitor, &a_statorVoltage, - &c_aa_statorVoltage); - mount_agentInAgent(&a_viabilityMonitor, &a_statorCurrent, - &c_aa_statorCurrent); - mount_agentInAgent(&a_viabilityMonitor, &a_speed, &c_aa_speed); - mount_agentInAgent(&a_viabilityMonitor, &a_electromagneticTorque, - &c_aa_electromagneticTorque); - mount_agentInAgent(&a_viabilityMonitor, &a_mechanicalTorque, - &c_aa_mechanicalTorque); - - // create testbench - printf("\nCreate Testbench\n"); - Testbench tb = create_testbench("testbench"); - - // csv-data - // TODO: (1) simplify constructor, (2) check CSV for number of rows and - // columns, (3) redesign create_CSVreaderModule function - printf("\nCreate CSV Reader Modules\n"); - CSVreaderModule csvr_statorVoltage = create_CSVreaderModule( - "Stator Voltage CSV-Reader", - "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\statorVoltage.csv", 2, - 2); - CSVreaderModule csvr_statorCurrent = create_CSVreaderModule( - "Stator Current CSV-Reader", - "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\statorCurrent.csv", 2, - 2); - CSVreaderModule csvr_speed = create_CSVreaderModule( - "Speed CSV-Reader", - "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\speed.csv", 2, 2); - CSVreaderModule csvr_electromagneticTorque = - create_CSVreaderModule("Electromagnetic Torque CSV-Reader", - "C:\\csv-data\\sambamotor\\Normal_operation-" - "Tm0\\electromagneticTorque.csv", - 2, 2); - CSVreaderModule csvr_mechanicalTorque = create_CSVreaderModule( - "Mechanical Torque CSV-Reader", - "C:\\csv-data\\sambamotor\\Normal_operation-Tm0\\mechanicalTorque.csv", 2, - 2); - - // register agents - printf("\nRegister Agents in Testbench\n"); - // TODO: "Test Bench" not "Testbench" - register_agentInTestbench(&tb, &a_statorVoltage); - register_agentInTestbench(&tb, &a_statorCurrent); - register_agentInTestbench(&tb, &a_speed); - register_agentInTestbench(&tb, &a_electromagneticTorque); - register_agentInTestbench(&tb, &a_mechanicalTorque); - register_agentInTestbench(&tb, &a_viabilityMonitor); - - // register sensors with their csv-readers - printf("\nRegister Sensors in Testbench\n"); - register_sensorInTestbench(&tb, &s_statorVoltage, &csvr_statorVoltage); - register_sensorInTestbench(&tb, &s_statorCurrent, &csvr_statorCurrent); - register_sensorInTestbench(&tb, &s_speed, &csvr_speed); - register_sensorInTestbench(&tb, &s_electromagneticTorque, - &csvr_electromagneticTorque); - register_sensorInTestbench(&tb, &s_mechanicalTorque, &csvr_mechanicalTorque); - - // register sensor channels - printf("\nRegister Channels in Testbench\n"); - register_channelInTestbench(&tb, &c_sa_statorVoltage); - register_channelInTestbench(&tb, &c_sa_statorCurrent); - register_channelInTestbench(&tb, &c_sa_speed); - register_channelInTestbench(&tb, &c_sa_electromagneticTorque); - register_channelInTestbench(&tb, &c_sa_mechanicalTorque); - register_channelInTestbench(&tb, &c_aa_statorVoltage); - register_channelInTestbench(&tb, &c_aa_statorCurrent); - register_channelInTestbench(&tb, &c_aa_speed); - register_channelInTestbench(&tb, &c_aa_electromagneticTorque); - register_channelInTestbench(&tb, &c_aa_mechanicalTorque); - - printf("\n\nPress any key to start simulation...\n"); - getchar(); - - // Start - // TODO: read lenght of CSV-Files and pass this number to tb.simulate - tb.simulate(29208); - getchar(); -} diff --git a/lib/gen_agent_test2/mount_nodes.cpp b/lib/gen_agent_test2/mount_nodes.cpp deleted file mode 100644 index cf748c0..0000000 --- a/lib/gen_agent_test2/mount_nodes.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "mount_nodes.h" -#include "attach_modules.h" -//#include "rlutil.h" -#include - -// using namespace rlutil; - -bool mount_sensorInAgent(Agent *agent, Sensor *sensor, Channel *channel) { - if (agent != NULL && sensor != NULL && channel != NULL) { - printf(" > Sensor "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", sensor->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", sensor->get_id()); - if (agent->get_sensorHandlerOfAgent()->mount_sensorIntoSensorSlot( - channel) && - sensor->mount_agent(channel)) { - // setColor(TXTCOLOR_LIGHTGREEN); - printf("mounted "); - // setColor(TXTCOLOR_GREY); - printf("in Agent "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", agent->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u)\n", agent->get_id()); - return true; - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("couldn't be mounted in %s (id: %03u)\n", agent->get_name(), - agent->get_id()); - // setColor(TXTCOLOR_GREY); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Agent, Sensor, or Channel is not valid\n"); - // setColor(TXTCOLOR_GREY); - } - return false; -} - -bool mount_sensorInAgent(Agent *agent, Sensor *sensor, Channel *channel, - HistoryModule *historyModule) { - if (agent != NULL && sensor != NULL && channel != NULL && - historyModule != NULL) { - if (mount_sensorInAgent(agent, sensor, channel)) { - return attach_historyModuleToSensorSlotInAgent(agent, sensor, channel, - historyModule); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("Agent, Sensor, Channel, or HistoryModule is not valid\n"); - // setColor(TXTCOLOR_GREY); - } - return false; -} - -bool mount_agentInAgent(Agent *masteragent, Agent *slaveagent, - Channel *channel) { - if (masteragent != NULL && slaveagent != NULL && channel != NULL) { - if (masteragent->get_slaveAgentHandlerOfAgent() - ->mount_slaveAgentIntoSlaveAgentSlot(channel)) { - if (slaveagent->get_masterAgentHandlerOfAgent() - ->mount_masterAgentIntoSlaveAgentSlot(channel)) { - printf(" > Agent "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", slaveagent->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", slaveagent->get_id()); - // setColor(TXTCOLOR_LIGHTGREEN); - printf("mounted "); - // setColor(TXTCOLOR_GREY); - printf("in Agent "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", masteragent->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u)\n", masteragent->get_id()); - return true; - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Could not mount Master Agent %s (id: %03u) in Slave Agent " - "%s (id: %03u)\n", - masteragent->get_name(), masteragent->get_id(), - slaveagent->get_name(), slaveagent->get_id()); - // setColor(TXTCOLOR_GREY); - masteragent->get_slaveAgentHandlerOfAgent() - ->demount_slaveAgentIntoSlaveAgentSlot(channel); - } - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > One of the Agents or Channel not valid\n"); - // setColor(TXTCOLOR_GREY); - } - return false; -} - diff --git a/lib/gen_agent_test2/mount_nodes.h b/lib/gen_agent_test2/mount_nodes.h deleted file mode 100644 index b102b44..0000000 --- a/lib/gen_agent_test2/mount_nodes.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MOUNT_NODES_HEADERFILE -#define MOUNT_NODES_HEADERFILE - -#include "Agent.h" -#include "ConfidenceModule.h" -#include "Sensor.h" - -bool mount_sensorInAgent(Agent *agent, Sensor *sensor, Channel *channel); -bool mount_sensorInAgent(Agent *agent, Sensor *sensor, Channel *channel, - HistoryModule *historyModule); - -bool mount_agentInAgent(Agent *masteragent, Agent *slaveagent, - Channel *channel); - -#endif diff --git a/lib/gen_agent_test2/printError.cpp b/lib/gen_agent_test2/printError.cpp deleted file mode 100644 index 57c2a07..0000000 --- a/lib/gen_agent_test2/printError.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "printError.h" -#include - -#define PC_MODE - -void printError(const char *errorMsg) { -#ifdef PC_MODE - printf("%s\n", errorMsg); -#endif -} - -void printError(const char *errorMsg, const char *additionalInfo) { -#ifdef PC_MODE - printf("%s: %s\n", errorMsg, additionalInfo); -#endif -} diff --git a/lib/gen_agent_test2/printError.h b/lib/gen_agent_test2/printError.h deleted file mode 100644 index 6b26a92..0000000 --- a/lib/gen_agent_test2/printError.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef PRINT_HEADERFILE -#define PRINT_HEADERFILE - -void printError(const char *); -void printError(const char *errorMsg, const char *additionalInfo); - -#endif diff --git a/lib/gen_agent_test2/register_in_testbench.cpp b/lib/gen_agent_test2/register_in_testbench.cpp deleted file mode 100644 index 2b7eea0..0000000 --- a/lib/gen_agent_test2/register_in_testbench.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "register_in_testbench.h" - -#include "attach_modulesToTestbench.h" -//#include "rlutil.h" -#include - -// using namespace rlutil; - -bool register_agentInTestbench(Testbench *tb, Agent *agent) { - if (tb != NULL && agent != NULL) { - printf(" > Agent "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", agent->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", agent->get_id()); - - if (tb->register_agent(agent)) { - // setColor(TXTCOLOR_LIGHTGREEN); - printf("registered "); - // setColor(TXTCOLOR_GREY); - printf("in Testbench "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s\n", tb->get_name()); - // setColor(TXTCOLOR_GREY); - return true; - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("couldn't be registered in %s", tb->get_name()); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Testbench or Agent is not valid\n"); - } - // setColor(TXTCOLOR_GREY); - return false; -} - -bool register_sensorInTestbench(Testbench *tb, Sensor *sensor) { - if (tb != NULL && sensor != NULL) { - printf(" > Sensor "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", sensor->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", sensor->get_id()); - if (tb->register_sensor(sensor)) { - // setColor(TXTCOLOR_LIGHTGREEN); - printf("registered "); - // setColor(TXTCOLOR_GREY); - printf("in "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s\n", tb->get_name()); - // setColor(TXTCOLOR_GREY); - return true; - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("couldn't be registered in %s\n", tb->get_name()); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf(" > Testbench or sensor is not valid\n"); - } - // setColor(TXTCOLOR_GREY); - return false; -} - -bool register_sensorInTestbench(Testbench *tb, Sensor *sensor, - CSVreaderModule *csvReaderModule) { - if (tb != NULL && sensor != NULL && csvReaderModule != NULL) { - if (register_sensorInTestbench(tb, sensor)) { - return attach_csvReaderModuleToSensorSlotInAgent(tb, sensor, - csvReaderModule); - } - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("Testbench or sensor is not valid\n"); - } - // setColor(TXTCOLOR_GREY); - return false; -} - -bool register_channelInTestbench(Testbench *tb, Channel *channel) { - printf(" > Channel "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s ", channel->get_name()); - // setColor(TXTCOLOR_GREY); - printf("(id: %03u) ", channel->get_id()); - - if (tb->register_channel(channel)) { - // setColor(TXTCOLOR_LIGHTGREEN); - printf("registered "); - // setColor(TXTCOLOR_GREY); - printf("in Testbench "); - // setColor(TXTCOLOR_LIGHTCYAN); - printf("%s\n", tb->get_name()); - } else { - // setColor(TXTCOLOR_LIGHTRED); - printf("couldn't be registered in %s\n", tb->get_name()); - } - // setColor(TXTCOLOR_GREY); - - return false; -} diff --git a/lib/gen_agent_test2/register_in_testbench.h b/lib/gen_agent_test2/register_in_testbench.h deleted file mode 100644 index ea35ed9..0000000 --- a/lib/gen_agent_test2/register_in_testbench.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef REGISTER_IN_TESTBENCH_HEADERFILE -#define REGISTER_IN_TESTBENCH_HEADERFILE - -#include "Testbench.h" - -bool register_agentInTestbench(Testbench *tb, Agent *agent); - -bool register_sensorInTestbench(Testbench *tb, Sensor *sensor); -bool register_sensorInTestbench(Testbench *tb, Sensor *sensor, - CSVreaderModule *csvReaderModule); - -bool register_channelInTestbench(Testbench *tb, Channel *channel); - -#endif diff --git a/lib/gen_agent_test2/rlutil.h b/lib/gen_agent_test2/rlutil.h deleted file mode 100644 index f19baf6..0000000 --- a/lib/gen_agent_test2/rlutil.h +++ /dev/null @@ -1,779 +0,0 @@ -#pragma once -/** - * File: rlutil.h - * - * About: Description - * This file provides some useful utilities for console mode - * roguelike game development with C and C++. It is aimed to - * be cross-platform (at least Windows and Linux). - * - * About: Copyright - * (C) 2010 Tapio Vierros - * - * About: Licensing - * See - */ - -//#ifndef RLUTIL_HEADERFILE -//#define RLUTIL_HEADERFILE - -/// Define: RLUTIL_USE_ANSI -/// Define this to use ANSI escape sequences also on Windows -/// (defaults to using WinAPI instead). -#if 0 -#define RLUTIL_USE_ANSI -#endif - -/// Define: RLUTIL_STRING_T -/// Define/typedef this to your preference to override rlutil's string type. -/// -/// Defaults to std::string with C++ and char* with C. -#if 0 -#define RLUTIL_STRING_T char* -#endif - -#ifndef RLUTIL_INLINE - #ifdef _MSC_VER - #define RLUTIL_INLINE __inline - #else - #define RLUTIL_INLINE static __inline__ - #endif -#endif - -#ifdef __cplusplus - /// Common C++ headers - #include - #include - #include // for getch() - /// Namespace forward declarations - namespace rlutil { - RLUTIL_INLINE void locate(int x, int y); - } - - //Work Arround (atartpoint) - - #define TXTCOLOR_BLACK 0 - #define TXTCOLOR_BLUE 1 - #define TXTCOLOR_GREEN 2 - #define TXTCOLOR_CYAN 3 - #define TXTCOLOR_RED 4 - #define TXTCOLOR_MAGENTA 5 - #define TXTCOLOR_BROWN 6 - #define TXTCOLOR_GREY 7 - #define TXTCOLOR_DARKGREY 8 - #define TXTCOLOR_LIGHTBLUE 9 - #define TXTCOLOR_LIGHTGREEN 10 - #define TXTCOLOR_LIGHTCYAN 11 - #define TXTCOLOR_LIGHTRED 12 - #define TXTCOLOR_LIGHTMAGENTA 13 - #define TXTCOLOR_YELLOW 14 - #define TXTCOLOR_WHITE 15 - -#else - #include // for getch() / printf() - #include // for strlen() - RLUTIL_INLINE void locate(int x, int y); // Forward declare for C to avoid warnings -#endif // __cplusplus - -#ifdef _WIN32 - #include // for WinAPI and Sleep() - #define _NO_OLDNAMES // for MinGW compatibility - #include // for getch() and kbhit() - #define getch _getch - #define kbhit _kbhit -#else - #include // for getch() and kbhit() - #include // for getch(), kbhit() and (u)sleep() - #include // for getkey() - #include // for kbhit() - #include // for kbhit() - -/// Function: getch -/// Get character without waiting for Return to be pressed. -/// Windows has this in conio.h -RLUTIL_INLINE int getch(void) { - // Here be magic. - struct termios oldt, newt; - int ch; - tcgetattr(STDIN_FILENO, &oldt); - newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - ch = getchar(); - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - return ch; -} - -/// Function: kbhit -/// Determines if keyboard has been hit. -/// Windows has this in conio.h -RLUTIL_INLINE int kbhit(void) { - // Here be dragons. - static struct termios oldt, newt; - int cnt = 0; - tcgetattr(STDIN_FILENO, &oldt); - newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - newt.c_iflag = 0; // input mode - newt.c_oflag = 0; // output mode - newt.c_cc[VMIN] = 1; // minimum time to wait - newt.c_cc[VTIME] = 1; // minimum characters to wait for - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - ioctl(0, FIONREAD, &cnt); // Read count - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100; - select(STDIN_FILENO+1, NULL, NULL, NULL, &tv); // A small time delay - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - return cnt; // Return number of characters -} -#endif // _WIN32 - -#ifndef gotoxy -/// Function: gotoxy -/// Same as . -RLUTIL_INLINE void gotoxy(int x, int y) { - #ifdef __cplusplus - rlutil:: - #endif - locate(x,y); -} -#endif // gotoxy - -#ifdef __cplusplus -/// Namespace: rlutil -/// In C++ all functions except , and are arranged -/// under namespace rlutil. That is because some platforms have them defined -/// outside of rlutil. -namespace rlutil { -#endif - -/** - * Defs: Internal typedefs and macros - * RLUTIL_STRING_T - String type depending on which one of C or C++ is used - * RLUTIL_PRINT(str) - Printing macro independent of C/C++ - */ - -#ifdef __cplusplus - #ifndef RLUTIL_STRING_T - typedef std::string RLUTIL_STRING_T; - #endif // RLUTIL_STRING_T - - #define RLUTIL_PRINT(st) do { std::cout << st; } while(false) -#else // __cplusplus - #ifndef RLUTIL_STRING_T - typedef const char* RLUTIL_STRING_T; - #endif // RLUTIL_STRING_T - - #define RLUTIL_PRINT(st) printf("%s", st) -#endif // __cplusplus - -/** - * Enums: Color codes - * - * BLACK - Black - * BLUE - Blue - * GREEN - Green - * CYAN - Cyan - * RED - Red - * MAGENTA - Magenta / purple - * BROWN - Brown / dark yellow - * GREY - Grey / dark white - * DARKGREY - Dark grey / light black - * LIGHTBLUE - Light blue - * LIGHTGREEN - Light green - * LIGHTCYAN - Light cyan - * LIGHTRED - Light red - * LIGHTMAGENTA - Light magenta / light purple - * YELLOW - Yellow (bright) - * WHITE - White (bright) - */ -enum { - BLACK, - BLUE, - GREEN, - CYAN, - RED, - MAGENTA, - BROWN, - GREY, - DARKGREY, - LIGHTBLUE, - LIGHTGREEN, - LIGHTCYAN, - LIGHTRED, - LIGHTMAGENTA, - YELLOW, - WHITE -}; - -/** - * Consts: ANSI escape strings - * - * ANSI_CLS - Clears screen - * ANSI_CONSOLE_TITLE_PRE - Prefix for changing the window title, print the window title in between - * ANSI_CONSOLE_TITLE_POST - Suffix for changing the window title, print the window title in between - * ANSI_ATTRIBUTE_RESET - Resets all attributes - * ANSI_CURSOR_HIDE - Hides the cursor - * ANSI_CURSOR_SHOW - Shows the cursor - * ANSI_CURSOR_HOME - Moves the cursor home (0,0) - * ANSI_BLACK - Black - * ANSI_RED - Red - * ANSI_GREEN - Green - * ANSI_BROWN - Brown / dark yellow - * ANSI_BLUE - Blue - * ANSI_MAGENTA - Magenta / purple - * ANSI_CYAN - Cyan - * ANSI_GREY - Grey / dark white - * ANSI_DARKGREY - Dark grey / light black - * ANSI_LIGHTRED - Light red - * ANSI_LIGHTGREEN - Light green - * ANSI_YELLOW - Yellow (bright) - * ANSI_LIGHTBLUE - Light blue - * ANSI_LIGHTMAGENTA - Light magenta / light purple - * ANSI_LIGHTCYAN - Light cyan - * ANSI_WHITE - White (bright) - * ANSI_BACKGROUND_BLACK - Black background - * ANSI_BACKGROUND_RED - Red background - * ANSI_BACKGROUND_GREEN - Green background - * ANSI_BACKGROUND_YELLOW - Yellow background - * ANSI_BACKGROUND_BLUE - Blue background - * ANSI_BACKGROUND_MAGENTA - Magenta / purple background - * ANSI_BACKGROUND_CYAN - Cyan background - * ANSI_BACKGROUND_WHITE - White background - */ -const RLUTIL_STRING_T ANSI_CLS = "\033[2J\033[3J"; -const RLUTIL_STRING_T ANSI_CONSOLE_TITLE_PRE = "\033]0;"; -const RLUTIL_STRING_T ANSI_CONSOLE_TITLE_POST = "\007"; -const RLUTIL_STRING_T ANSI_ATTRIBUTE_RESET = "\033[0m"; -const RLUTIL_STRING_T ANSI_CURSOR_HIDE = "\033[?25l"; -const RLUTIL_STRING_T ANSI_CURSOR_SHOW = "\033[?25h"; -const RLUTIL_STRING_T ANSI_CURSOR_HOME = "\033[H"; -const RLUTIL_STRING_T ANSI_BLACK = "\033[22;30m"; -const RLUTIL_STRING_T ANSI_RED = "\033[22;31m"; -const RLUTIL_STRING_T ANSI_GREEN = "\033[22;32m"; -const RLUTIL_STRING_T ANSI_BROWN = "\033[22;33m"; -const RLUTIL_STRING_T ANSI_BLUE = "\033[22;34m"; -const RLUTIL_STRING_T ANSI_MAGENTA = "\033[22;35m"; -const RLUTIL_STRING_T ANSI_CYAN = "\033[22;36m"; -const RLUTIL_STRING_T ANSI_GREY = "\033[22;37m"; -const RLUTIL_STRING_T ANSI_DARKGREY = "\033[01;30m"; -const RLUTIL_STRING_T ANSI_LIGHTRED = "\033[01;31m"; -const RLUTIL_STRING_T ANSI_LIGHTGREEN = "\033[01;32m"; -const RLUTIL_STRING_T ANSI_YELLOW = "\033[01;33m"; -const RLUTIL_STRING_T ANSI_LIGHTBLUE = "\033[01;34m"; -const RLUTIL_STRING_T ANSI_LIGHTMAGENTA = "\033[01;35m"; -const RLUTIL_STRING_T ANSI_LIGHTCYAN = "\033[01;36m"; -const RLUTIL_STRING_T ANSI_WHITE = "\033[01;37m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_BLACK = "\033[40m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_RED = "\033[41m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_GREEN = "\033[42m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_YELLOW = "\033[43m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_BLUE = "\033[44m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_MAGENTA = "\033[45m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_CYAN = "\033[46m"; -const RLUTIL_STRING_T ANSI_BACKGROUND_WHITE = "\033[47m"; -// Remaining colors not supported as background colors - -/** - * Enums: Key codes for keyhit() - * - * KEY_ESCAPE - Escape - * KEY_ENTER - Enter - * KEY_SPACE - Space - * KEY_INSERT - Insert - * KEY_HOME - Home - * KEY_END - End - * KEY_DELETE - Delete - * KEY_PGUP - PageUp - * KEY_PGDOWN - PageDown - * KEY_UP - Up arrow - * KEY_DOWN - Down arrow - * KEY_LEFT - Left arrow - * KEY_RIGHT - Right arrow - * KEY_F1 - F1 - * KEY_F2 - F2 - * KEY_F3 - F3 - * KEY_F4 - F4 - * KEY_F5 - F5 - * KEY_F6 - F6 - * KEY_F7 - F7 - * KEY_F8 - F8 - * KEY_F9 - F9 - * KEY_F10 - F10 - * KEY_F11 - F11 - * KEY_F12 - F12 - * KEY_NUMDEL - Numpad del - * KEY_NUMPAD0 - Numpad 0 - * KEY_NUMPAD1 - Numpad 1 - * KEY_NUMPAD2 - Numpad 2 - * KEY_NUMPAD3 - Numpad 3 - * KEY_NUMPAD4 - Numpad 4 - * KEY_NUMPAD5 - Numpad 5 - * KEY_NUMPAD6 - Numpad 6 - * KEY_NUMPAD7 - Numpad 7 - * KEY_NUMPAD8 - Numpad 8 - * KEY_NUMPAD9 - Numpad 9 - */ -enum { - KEY_ESCAPE = 0, - KEY_ENTER = 1, - KEY_SPACE = 32, - - KEY_INSERT = 2, - KEY_HOME = 3, - KEY_PGUP = 4, - KEY_DELETE = 5, - KEY_END = 6, - KEY_PGDOWN = 7, - - KEY_UP = 14, - KEY_DOWN = 15, - KEY_LEFT = 16, - KEY_RIGHT = 17, - - KEY_F1 = 18, - KEY_F2 = 19, - KEY_F3 = 20, - KEY_F4 = 21, - KEY_F5 = 22, - KEY_F6 = 23, - KEY_F7 = 24, - KEY_F8 = 25, - KEY_F9 = 26, - KEY_F10 = 27, - KEY_F11 = 28, - KEY_F12 = 29, - - KEY_NUMDEL = 30, - KEY_NUMPAD0 = 31, - KEY_NUMPAD1 = 127, - KEY_NUMPAD2 = 128, - KEY_NUMPAD3 = 129, - KEY_NUMPAD4 = 130, - KEY_NUMPAD5 = 131, - KEY_NUMPAD6 = 132, - KEY_NUMPAD7 = 133, - KEY_NUMPAD8 = 134, - KEY_NUMPAD9 = 135 -}; - -/// Function: getkey -/// Reads a key press (blocking) and returns a key code. -/// -/// See -/// -/// Note: -/// Only Arrows, Esc, Enter and Space are currently working properly. -RLUTIL_INLINE int getkey(void) { - #ifndef _WIN32 - int cnt = kbhit(); // for ANSI escapes processing - #endif - int k = getch(); - switch(k) { - case 0: { - int kk; - switch (kk = getch()) { - case 71: return KEY_NUMPAD7; - case 72: return KEY_NUMPAD8; - case 73: return KEY_NUMPAD9; - case 75: return KEY_NUMPAD4; - case 77: return KEY_NUMPAD6; - case 79: return KEY_NUMPAD1; - case 80: return KEY_NUMPAD2; - case 81: return KEY_NUMPAD3; - case 82: return KEY_NUMPAD0; - case 83: return KEY_NUMDEL; - default: return kk-59+KEY_F1; // Function keys - }} - case 224: { - int kk; - switch (kk = getch()) { - case 71: return KEY_HOME; - case 72: return KEY_UP; - case 73: return KEY_PGUP; - case 75: return KEY_LEFT; - case 77: return KEY_RIGHT; - case 79: return KEY_END; - case 80: return KEY_DOWN; - case 81: return KEY_PGDOWN; - case 82: return KEY_INSERT; - case 83: return KEY_DELETE; - default: return kk-123+KEY_F1; // Function keys - }} - case 13: return KEY_ENTER; -#ifdef _WIN32 - case 27: return KEY_ESCAPE; -#else // _WIN32 - case 155: // single-character CSI - case 27: { - // Process ANSI escape sequences - if (cnt >= 3 && getch() == '[') { - switch (k = getch()) { - case 'A': return KEY_UP; - case 'B': return KEY_DOWN; - case 'C': return KEY_RIGHT; - case 'D': return KEY_LEFT; - } - } else return KEY_ESCAPE; - } -#endif // _WIN32 - default: return k; - } -} - -/// Function: nb_getch -/// Non-blocking getch(). Returns 0 if no key was pressed. -RLUTIL_INLINE int nb_getch(void) { - if (kbhit()) return getch(); - else return 0; -} - -/// Function: getANSIColor -/// Return ANSI color escape sequence for specified number 0-15. -/// -/// See -RLUTIL_INLINE RLUTIL_STRING_T getANSIColor(const int c) { - switch (c) { - case BLACK : return ANSI_BLACK; - case BLUE : return ANSI_BLUE; // non-ANSI - case GREEN : return ANSI_GREEN; - case CYAN : return ANSI_CYAN; // non-ANSI - case RED : return ANSI_RED; // non-ANSI - case MAGENTA : return ANSI_MAGENTA; - case BROWN : return ANSI_BROWN; - case GREY : return ANSI_GREY; - case DARKGREY : return ANSI_DARKGREY; - case LIGHTBLUE : return ANSI_LIGHTBLUE; // non-ANSI - case LIGHTGREEN : return ANSI_LIGHTGREEN; - case LIGHTCYAN : return ANSI_LIGHTCYAN; // non-ANSI; - case LIGHTRED : return ANSI_LIGHTRED; // non-ANSI; - case LIGHTMAGENTA: return ANSI_LIGHTMAGENTA; - case YELLOW : return ANSI_YELLOW; // non-ANSI - case WHITE : return ANSI_WHITE; - default: return ""; - } -} - -/// Function: getANSIBackgroundColor -/// Return ANSI background color escape sequence for specified number 0-15. -/// -/// See -RLUTIL_INLINE RLUTIL_STRING_T getANSIBackgroundColor(const int c) { - switch (c) { - case BLACK : return ANSI_BACKGROUND_BLACK; - case BLUE : return ANSI_BACKGROUND_BLUE; - case GREEN : return ANSI_BACKGROUND_GREEN; - case CYAN : return ANSI_BACKGROUND_CYAN; - case RED : return ANSI_BACKGROUND_RED; - case MAGENTA: return ANSI_BACKGROUND_MAGENTA; - case BROWN : return ANSI_BACKGROUND_YELLOW; - case GREY : return ANSI_BACKGROUND_WHITE; - default: return ""; - } -} - -/// Function: setColor -/// Change color specified by number (Windows / QBasic colors). -/// Don't change the background color -/// -/// See -RLUTIL_INLINE void setColor(int c) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO csbi; - - GetConsoleScreenBufferInfo(hConsole, &csbi); - - SetConsoleTextAttribute(hConsole, (csbi.wAttributes & 0xFFF0) | (WORD)c); // Foreground colors take up the least significant byte -#else - RLUTIL_PRINT(getANSIColor(c)); -#endif -} - -/// Function: setBackgroundColor -/// Change background color specified by number (Windows / QBasic colors). -/// Don't change the foreground color -/// -/// See -RLUTIL_INLINE void setBackgroundColor(int c) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO csbi; - - GetConsoleScreenBufferInfo(hConsole, &csbi); - - SetConsoleTextAttribute(hConsole, (csbi.wAttributes & 0xFF0F) | (((WORD)c) << 4)); // Background colors take up the second-least significant byte -#else - RLUTIL_PRINT(getANSIBackgroundColor(c)); -#endif -} - -/// Function: saveDefaultColor -/// Call once to preserve colors for use in resetColor() -/// on Windows without ANSI, no-op otherwise -/// -/// See -/// See -RLUTIL_INLINE int saveDefaultColor(void) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - static char initialized = 0; // bool - static WORD attributes; - - if (!initialized) { - CONSOLE_SCREEN_BUFFER_INFO csbi; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); - attributes = csbi.wAttributes; - initialized = 1; - } - return (int)attributes; -#else - return -1; -#endif -} - -/// Function: resetColor -/// Reset color to default -/// Requires a call to saveDefaultColor() to set the defaults -/// -/// See -/// See -/// See -RLUTIL_INLINE void resetColor(void) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (WORD)saveDefaultColor()); -#else - RLUTIL_PRINT(ANSI_ATTRIBUTE_RESET); -#endif -} - -/// Function: cls -/// Clears screen, resets all attributes and moves cursor home. -RLUTIL_INLINE void cls(void) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - // Based on https://msdn.microsoft.com/en-us/library/windows/desktop/ms682022%28v=vs.85%29.aspx - const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - const COORD coordScreen = {0, 0}; - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - - GetConsoleScreenBufferInfo(hConsole, &csbi); - const DWORD dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - FillConsoleOutputCharacter(hConsole, (TCHAR)' ', dwConSize, coordScreen, &cCharsWritten); - - GetConsoleScreenBufferInfo(hConsole, &csbi); - FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); - - SetConsoleCursorPosition(hConsole, coordScreen); -#else - RLUTIL_PRINT(ANSI_CLS); - RLUTIL_PRINT(ANSI_CURSOR_HOME); -#endif -} - -/// Function: locate -/// Sets the cursor position to 1-based x,y. -RLUTIL_INLINE void locate(int x, int y) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - COORD coord; - // TODO: clamping/assert for x/y <= 0? - coord.X = (SHORT)(x - 1); - coord.Y = (SHORT)(y - 1); // Windows uses 0-based coordinates - SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); -#else // _WIN32 || USE_ANSI - #ifdef __cplusplus - RLUTIL_PRINT("\033[" << y << ";" << x << "H"); - #else // __cplusplus - char buf[32]; - sprintf(buf, "\033[%d;%df", y, x); - RLUTIL_PRINT(buf); - #endif // __cplusplus -#endif // _WIN32 || USE_ANSI -} - -/// Function: setString -/// Prints the supplied string without advancing the cursor -#ifdef __cplusplus - -RLUTIL_INLINE void setString(const RLUTIL_STRING_T & str_) { - - //Work Around (startpoint) - const char * const str_temp = str_.data(); //Changed: "str" -> "str_temp" - wchar_t* str=new wchar_t[4096]; //Add this line - MultiByteToWideChar(CP_ACP, 0, str_temp, -1, str, 4096); //Add this line - //Work Around (endpoint) - - unsigned int len = str_.size(); -#else // __cplusplus -RLUTIL_INLINE void setString(RLUTIL_STRING_T str) { - unsigned int len = strlen(str); -#endif // __cplusplus -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD numberOfCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - - GetConsoleScreenBufferInfo(hConsoleOutput, &csbi); - WriteConsoleOutputCharacter(hConsoleOutput, str, len, csbi.dwCursorPosition, &numberOfCharsWritten); -#else // _WIN32 || USE_ANSI - RLUTIL_PRINT(str); - #ifdef __cplusplus - RLUTIL_PRINT("\033[" << len << 'D'); - #else // __cplusplus - char buf[3 + 20 + 1]; // 20 = max length of 64-bit unsigned int when printed as dec - sprintf(buf, "\033[%uD", len); - RLUTIL_PRINT(buf); - #endif // __cplusplus -#endif // _WIN32 || USE_ANSI -} - -/// Function: setChar -/// Sets the character at the cursor without advancing the cursor -RLUTIL_INLINE void setChar(char ch) { - const char buf[] = {ch, 0}; - setString(buf); -} - -/// Function: setCursorVisibility -/// Shows/hides the cursor. -RLUTIL_INLINE void setCursorVisibility(char visible) { -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - HANDLE hConsoleOutput = GetStdHandle( STD_OUTPUT_HANDLE ); - CONSOLE_CURSOR_INFO structCursorInfo; - GetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); // Get current cursor size - structCursorInfo.bVisible = (visible ? TRUE : FALSE); - SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); -#else // _WIN32 || USE_ANSI - RLUTIL_PRINT((visible ? ANSI_CURSOR_SHOW : ANSI_CURSOR_HIDE)); -#endif // _WIN32 || USE_ANSI -} - -/// Function: hidecursor -/// Hides the cursor. -RLUTIL_INLINE void hidecursor(void) { - setCursorVisibility(0); -} - -/// Function: showcursor -/// Shows the cursor. -RLUTIL_INLINE void showcursor(void) { - setCursorVisibility(1); -} - -/// Function: msleep -/// Waits given number of milliseconds before continuing. -RLUTIL_INLINE void msleep(unsigned int ms) { -#ifdef _WIN32 - Sleep(ms); -#else - // usleep argument must be under 1 000 000 - if (ms > 1000) sleep(ms/1000000); - usleep((ms % 1000000) * 1000); -#endif -} - -/// Function: trows -/// Get the number of rows in the terminal window or -1 on error. -RLUTIL_INLINE int trows(void) { -#ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - return -1; - else - return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; // Window height - // return csbi.dwSize.Y; // Buffer height -#else -#ifdef TIOCGSIZE - struct ttysize ts; - ioctl(STDIN_FILENO, TIOCGSIZE, &ts); - return ts.ts_lines; -#elif defined(TIOCGWINSZ) - struct winsize ts; - ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); - return ts.ws_row; -#else // TIOCGSIZE - return -1; -#endif // TIOCGSIZE -#endif // _WIN32 -} - -/// Function: tcols -/// Get the number of columns in the terminal window or -1 on error. -RLUTIL_INLINE int tcols(void) { -#ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - return -1; - else - return csbi.srWindow.Right - csbi.srWindow.Left + 1; // Window width - // return csbi.dwSize.X; // Buffer width -#else -#ifdef TIOCGSIZE - struct ttysize ts; - ioctl(STDIN_FILENO, TIOCGSIZE, &ts); - return ts.ts_cols; -#elif defined(TIOCGWINSZ) - struct winsize ts; - ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); - return ts.ws_col; -#else // TIOCGSIZE - return -1; -#endif // TIOCGSIZE -#endif // _WIN32 -} - -/// Function: anykey -/// Waits until a key is pressed. -/// In C++, it either takes no arguments -/// or a template-type-argument-deduced -/// argument. -/// In C, it takes a const char* representing -/// the message to be displayed, or NULL -/// for no message. -#ifdef __cplusplus -RLUTIL_INLINE void anykey() { - getch(); -} - -template void anykey(const T& msg) { - RLUTIL_PRINT(msg); -#else -RLUTIL_INLINE void anykey(RLUTIL_STRING_T msg) { - if (msg) - RLUTIL_PRINT(msg); -#endif // __cplusplus - getch(); -} - -RLUTIL_INLINE void setConsoleTitle(RLUTIL_STRING_T title) { - const char * true_title = -#ifdef __cplusplus - title.c_str(); -#else // __cplusplus - title; -#endif // __cplusplus -#if defined(_WIN32) && !defined(RLUTIL_USE_ANSI) - SetConsoleTitleA(true_title); -#else - RLUTIL_PRINT(ANSI_CONSOLE_TITLE_PRE); - RLUTIL_PRINT(true_title); - RLUTIL_PRINT(ANSI_CONSOLE_TITLE_POST); -#endif // defined(_WIN32) && !defined(RLUTIL_USE_ANSI) -} - -// Classes are here at the end so that documentation is pretty. - -#ifdef __cplusplus -/// Class: CursorHider -/// RAII OOP wrapper for . -/// Hides the cursor and shows it again -/// when the object goes out of scope. -struct CursorHider { - CursorHider() { hidecursor(); } - ~CursorHider() { showcursor(); } -}; - -} // namespace rlutil -#endif - -//#endif \ No newline at end of file diff --git a/lib/support/CMakeLists.txt b/lib/support/CMakeLists.txt index 2f22fa7..1a7ea9b 100644 --- a/lib/support/CMakeLists.txt +++ b/lib/support/CMakeLists.txt @@ -1,28 +1,32 @@ set(LIB_INCLUDE_DIR ${ROSA_MAIN_INCLUDE_DIR}/rosa/support) add_library(ROSASupport ${LIB_INCLUDE_DIR}/debug.hpp debug.cpp ${LIB_INCLUDE_DIR}/terminal_colors.h terminal_colors.cpp ${LIB_INCLUDE_DIR}/log.h log.cpp ${LIB_INCLUDE_DIR}/math.hpp math.cpp ${LIB_INCLUDE_DIR}/type_helper.hpp type_helper.cpp ${LIB_INCLUDE_DIR}/types.hpp types.cpp ${LIB_INCLUDE_DIR}/atom.hpp atom.cpp ${LIB_INCLUDE_DIR}/type_pair.hpp type_pair.cpp ${LIB_INCLUDE_DIR}/type_list.hpp type_list.cpp ${LIB_INCLUDE_DIR}/squashed_int.hpp squashed_int.cpp ${LIB_INCLUDE_DIR}/type_numbers.hpp type_numbers.cpp ${LIB_INCLUDE_DIR}/type_token.hpp type_token.cpp + ${LIB_INCLUDE_DIR}/tokenized_storages.hpp + tokenized_storages.cpp + ${LIB_INCLUDE_DIR}/sequence.hpp + sequence.cpp ) diff --git a/lib/support/sequence.cpp b/lib/support/sequence.cpp new file mode 100755 index 0000000..1c738f5 --- /dev/null +++ b/lib/support/sequence.cpp @@ -0,0 +1,20 @@ +//===-- support/sequence.cpp ------------------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file support/sequence.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation for rosa/support/sequence.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/support/sequence.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/support/sequence.hpp" diff --git a/lib/support/tokenized_storages.cpp b/lib/support/tokenized_storages.cpp new file mode 100755 index 0000000..ceb8a47 --- /dev/null +++ b/lib/support/tokenized_storages.cpp @@ -0,0 +1,20 @@ +//===-- support/tokenized_storages.cpp --------------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file support/tokenized_storages.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2017 +/// +/// \brief Implementation of rosa/support/tokenized_storages.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/support/tokenized_storages.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/support/tokenized_storages.hpp" diff --git a/lib/support/type_token.cpp b/lib/support/type_token.cpp index 9436c78..30c37c7 100644 --- a/lib/support/type_token.cpp +++ b/lib/support/type_token.cpp @@ -1,131 +1,131 @@ //===-- support/type_token.cpp ----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file support/type_token.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Implementation for rosa/support/type_token.hpp. /// /// \todo Automatically generate proper cases for the switches with a big number /// of handcrafted similar cases in them. /// //===----------------------------------------------------------------------===// #include "rosa/support/type_token.hpp" namespace rosa { using namespace token; bool validToken(const Token T) { Token TT = T; bool Valid = true; while (Valid && !emptyToken(TT)) { - Valid &= validTypeNumber(typeNumberOfHeadOfToken(TT)); + Valid &= validTypeNumber(headOfToken(TT)); dropHeadOfToken(TT); } return Valid; } bool emptyToken(const Token T) { return static_cast(T) == 0; } size_t lengthOfToken(const Token T) { Token TT = T; size_t N = 0; while (!emptyToken(TT)) { ++N; dropHeadOfToken(TT); } return N; } size_t sizeOfValuesOfToken(const Token T) { ASSERT(validToken(T)); Token TT = T; size_t S = 0; while (!emptyToken(TT)) { S += sizeOfHeadOfToken(TT); dropHeadOfToken(TT); } return S; } #define SIZECASE(N) \ { \ case N: \ return TypeForNumber(N)>::Size; \ } size_t sizeOfHeadOfToken(const Token T) { ASSERT(!emptyToken(T) && validToken(T)); - switch (static_cast(typeNumberOfHeadOfToken(T))) { + switch (static_cast(headOfToken(T))) { default: { // Should never come here when \p T is valid and the case-list below covers // \c rosa::BuiltinTypes. ROSA_CRITICAL("unknown type number"); } SIZECASE(1); SIZECASE(2); SIZECASE(3); SIZECASE(4); SIZECASE(5); SIZECASE(6); SIZECASE(7); SIZECASE(8); SIZECASE(9); SIZECASE(10); SIZECASE(11); SIZECASE(12); SIZECASE(13); SIZECASE(14); SIZECASE(15); } } #define NAMECASE(N) \ { \ case N: \ return TypeForNumber(N)>::Name; \ } const char *nameOfHeadOfToken(const Token T) { ASSERT(!emptyToken(T) && validToken(T)); - switch (static_cast(typeNumberOfHeadOfToken(T))) { + switch (static_cast(headOfToken(T))) { default: { // Should never come here when \p T is valid and the case-list below covers // \c rosa::BuiltinTypes. ROSA_CRITICAL("unknown type number"); } NAMECASE(1); NAMECASE(2); NAMECASE(3); NAMECASE(4); NAMECASE(5); NAMECASE(6); NAMECASE(7); NAMECASE(8); NAMECASE(9); NAMECASE(10); NAMECASE(11); NAMECASE(12); NAMECASE(13); NAMECASE(14); NAMECASE(15); } } void dropHeadOfToken(Token &T) { T = static_cast(static_cast(T) >> RepresentationBits); } void dropNOfToken(Token &T, const size_t N) { T = static_cast(static_cast(T) >> (N * RepresentationBits)); } } // End namespace rosa