diff --git a/.clang-tidy b/.clang-tidy index 80f85bff16..78f0597f4d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -22,6 +22,7 @@ Checks: " -hicpp-avoid-c-arrays, -hicpp-no-array-decay, clang-analyzer-*, + clang-diagnostic*, bugprone-*, -bugprone-narrowing-conversions, -bugprone-easily-swappable-parameters, @@ -62,6 +63,7 @@ WarningsAsErrors: " -hicpp-no-array-decay, clang-analyzer-*, -clang-analyzer-optin.cplusplus.VirtualCall, + clang-diagnostic*, bugprone-*, -bugprone-narrowing-conversions, -bugprone-easily-swappable-parameters, diff --git a/scripts/generateHelicsH.py b/scripts/generateHelicsH.py index 0b24f6ced1..68160da0dd 100755 --- a/scripts/generateHelicsH.py +++ b/scripts/generateHelicsH.py @@ -3,7 +3,7 @@ """ Created on Mon Dec 7 14:25:17 2020 -@author: phlpt +@author: Philip Top """ import re @@ -73,6 +73,7 @@ "src/helics/shared_api_library/api-data.h", "src/helics/shared_api_library/helicsData.h", "src/helics/shared_api_library/helicsCore.h", + "src/helics/shared_api_library/helicsApps.h", "src/helics/shared_api_library/ValueFederate.h", "src/helics/shared_api_library/MessageFederate.h", "src/helics/shared_api_library/MessageFilters.h", diff --git a/src/helics/application_api/helicsTypes.hpp b/src/helics/application_api/helicsTypes.hpp index 6319ef6ef9..a233aa700a 100644 --- a/src/helics/application_api/helicsTypes.hpp +++ b/src/helics/application_api/helicsTypes.hpp @@ -496,7 +496,7 @@ inline X invalidValue() } /// defined constant for an invalid value as a double -constexpr double invalidDouble = -1e49; +constexpr double invalidDouble = HELICS_INVALID_DOUBLE; template<> constexpr double invalidValue() diff --git a/src/helics/apps/helicsApp.cpp b/src/helics/apps/helicsApp.cpp index ed1ff9bee6..976e7f459a 100644 --- a/src/helics/apps/helicsApp.cpp +++ b/src/helics/apps/helicsApp.cpp @@ -154,35 +154,36 @@ std::vector AppTextParser::preParseFile(const std::vector& klines) if (str.empty()) { continue; } - auto fc = str.find_first_not_of(" \t\n\r\0"); - if (fc == std::string::npos) { + auto firstChar = str.find_first_not_of(" \t\n\r\0"); + if (firstChar == std::string::npos) { continue; } if (inMline) { - if (fc + 2 < str.size()) { - if ((str[fc] == '#') && (str[fc + 1] == '#') && (str[fc + 2] == ']')) { + if (firstChar + 2 < str.size()) { + if ((str[firstChar] == '#') && (str[firstChar + 1] == '#') && + (str[firstChar + 2] == ']')) { inMline = false; } } continue; } - if (str[fc] == '#') { - if (fc + 2 < str.size()) { - if ((str[fc + 1] == '#') && (str[fc + 2] == '[')) { + if (str[firstChar] == '#') { + if (firstChar + 2 < str.size()) { + if ((str[firstChar + 1] == '#') && (str[firstChar + 2] == '[')) { inMline = true; } } continue; } - if (str[fc] == '!') { - configStr += str.substr(fc + 1); + if (str[firstChar] == '!') { + configStr += str.substr(firstChar + 1); configStr.push_back('\n'); continue; } ++counts[0]; for (std::size_t ii = 0; ii < klines.size(); ++ii) { - if (str[fc] == klines[ii]) { + if (str[firstChar] == klines[ii]) { ++counts[ii + 1]; } } @@ -277,15 +278,15 @@ void App::loadJsonFileConfiguration(const std::string& appName, auto doc = fileops::loadJson(jsonString); if (doc.contains("app")) { - auto appConfig = doc["app"]; + auto& appConfig = doc["app"]; loadConfigOptions(appConfig); } if (doc.contains("config")) { - auto appConfig = doc["config"]; + auto& appConfig = doc["config"]; loadConfigOptions(appConfig); } if (doc.contains(appName)) { - auto appConfig = doc[appName]; + auto& appConfig = doc[appName]; loadConfigOptions(appConfig); } } diff --git a/src/helics/apps/helicsApp.hpp b/src/helics/apps/helicsApp.hpp index fa3449f967..e20afca1ac 100644 --- a/src/helics/apps/helicsApp.hpp +++ b/src/helics/apps/helicsApp.hpp @@ -111,6 +111,9 @@ necessary /** get a const reference to the federate*/ const CombinationFederate& accessUnderlyingFederate() const { return *fed; } + /** get a copy of the federate pointer (this can be dangerous if misused) */ + std::shared_ptr getUnderlyingFederatePointer() { return fed; } + protected: /** load from a jsonString @param jsonString either a JSON filename or a string containing JSON diff --git a/src/helics/cxx_shared_library/cxx_file_list.cmake b/src/helics/cxx_shared_library/cxx_file_list.cmake index 7b3a0b4067..974ca1f4fd 100644 --- a/src/helics/cxx_shared_library/cxx_file_list.cmake +++ b/src/helics/cxx_shared_library/cxx_file_list.cmake @@ -78,6 +78,7 @@ set(helics_apps_public_headers ${HELICS_LIBRARY_SOURCE_DIR}/apps/Source.hpp ${HELICS_LIBRARY_SOURCE_DIR}/apps/Tracer.hpp ${HELICS_LIBRARY_SOURCE_DIR}/apps/helicsApp.hpp + ${HELICS_LIBRARY_SOURCE_DIR}/apps/Probe.hpp ${HELICS_LIBRARY_SOURCE_DIR}/apps/Connector.hpp ${HELICS_LIBRARY_SOURCE_DIR}/apps/Clone.hpp ${HELICS_LIBRARY_SOURCE_DIR}/apps/CoreApp.hpp diff --git a/src/helics/helics_apps.hpp b/src/helics/helics_apps.hpp index 7ccf57d1e1..a709fd1670 100644 --- a/src/helics/helics_apps.hpp +++ b/src/helics/helics_apps.hpp @@ -11,9 +11,11 @@ Header file for inclusion of the entire apps library #pragma once #include "apps/BrokerApp.hpp" +#include "apps/Clone.hpp" #include "apps/Connector.hpp" #include "apps/Echo.hpp" #include "apps/Player.hpp" +#include "apps/Probe.hpp" #include "apps/Recorder.hpp" #include "apps/Source.hpp" #include "apps/Tracer.hpp" diff --git a/src/helics/helics_enums.h b/src/helics/helics_enums.h index 9646a1beb1..55a7f14909 100644 --- a/src/helics/helics_enums.h +++ b/src/helics/helics_enums.h @@ -434,6 +434,8 @@ typedef enum { /* NOLINT */ #define HELICS_BIG_NUMBER 9223372036.854774 const double cHelicsBigNumber = HELICS_BIG_NUMBER; +#define HELICS_INVALID_DOUBLE -1E49 + #ifdef __cplusplus } /* end of extern "C" { */ #endif diff --git a/src/helics/shared_api_library/.clang-tidy b/src/helics/shared_api_library/.clang-tidy index 69bcd3272c..7f846fb356 100644 --- a/src/helics/shared_api_library/.clang-tidy +++ b/src/helics/shared_api_library/.clang-tidy @@ -19,13 +19,16 @@ Checks: " clang-analyzer-*, bugprone-*, -bugprone-narrowing-conversions, + -bugprone-easily-swappable-parameters, misc-*, -misc-non-private-member-variables-in-classes, + -misc-include-cleaner, cert-*, -cert-err58-cpp, portability-*, readability-*, -readability-magic-numbers, + -readability-avoid-unconditional-preprocessor-if, performance-* " @@ -50,10 +53,12 @@ WarningsAsErrors: " -bugprone-easily-swappable-parameters, misc-*, -misc-non-private-member-variables-in-classes, + -misc-include-cleaner, portability-*, readability-*, -readability-magic-numbers, -readability-identifier-naming, + -readability-avoid-unconditional-preprocessor-if, performance-* " diff --git a/src/helics/shared_api_library/CMakeLists.txt b/src/helics/shared_api_library/CMakeLists.txt index 62979387dd..f645e91fc5 100644 --- a/src/helics/shared_api_library/CMakeLists.txt +++ b/src/helics/shared_api_library/CMakeLists.txt @@ -16,6 +16,7 @@ set(helicsShared_headers MessageFilters.h Translators.h helicsCallbacks.h + helicsApps.h ) set(helicsShared_sources @@ -30,6 +31,12 @@ set(helicsShared_sources internal/api_objects.h ) +if(TARGET HELICS::apps) + list(APPEND helicsShared_sources helicsAppsExport.cpp) +else() + list(APPEND helicsShared_sources helicsAppsExportNull.cpp) +endif() + include(GenerateExportHeader) if(Python_EXECUTABLE) @@ -46,6 +53,7 @@ if(Python_EXECUTABLE) Translators.h helicsData.h helicsCore.h + helicsApps.h Translators.h api-data.h ../helics_enums.h @@ -109,33 +117,29 @@ set_target_properties(helics PROPERTIES VERSION ${HELICS_VERSION} SOVERSION ${HE set_target_properties(helics PROPERTIES CXX_VISIBILITY_PRESET hidden C_VISIBILITY_PRESET hidden) target_link_libraries(helics PRIVATE helics_application_api) +if(TARGET HELICS::apps) + target_link_libraries(helics PRIVATE HELICS::apps) +endif() target_link_libraries(helics PRIVATE compile_flags_target) -if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.0) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") target_compile_options(helics PUBLIC -Wno-documentation) endif() if(UNIX OR MINGW) if(NOT APPLE) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18) - include(CheckLinkerFlag) - check_linker_flag( - CXX "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.txt" - flag_linker_version_script - ) - if(flag_linker_version_script) - target_link_libraries( - helics PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.txt - ) - endif() - check_linker_flag(CXX "-Wl,--exclude-libs,ALL" flag_linker_exclude_libs) - if(flag_linker_exclude_libs) - target_link_libraries(helics PRIVATE -Wl,--exclude-libs,ALL) - endif() - else() + include(CheckLinkerFlag) + check_linker_flag( + CXX "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.txt" + flag_linker_version_script + ) + if(flag_linker_version_script) target_link_libraries( helics PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.txt ) + endif() + check_linker_flag(CXX "-Wl,--exclude-libs,ALL" flag_linker_exclude_libs) + if(flag_linker_exclude_libs) target_link_libraries(helics PRIVATE -Wl,--exclude-libs,ALL) endif() else(NOT_APPLE) diff --git a/src/helics/shared_api_library/FederateExport.cpp b/src/helics/shared_api_library/FederateExport.cpp index 537fe55ea6..66a6b3a7c0 100644 --- a/src/helics/shared_api_library/FederateExport.cpp +++ b/src/helics/shared_api_library/FederateExport.cpp @@ -5,10 +5,14 @@ additional details. All rights reserved. SPDX-License-Identifier: BSD-3-Clause */ +#include "../application_api/FederateInfo.hpp" +#include "../core/CoreTypes.hpp" #include "../core/core-exceptions.hpp" #include "../core/coreTypeOperations.hpp" #include "../helics.hpp" +#include "api-data.h" #include "gmlc/concurrency/TripWire.hpp" +#include "helics/helics_enums.h" #include "helicsCallbacks.h" #include "helicsCore.h" #include "internal/api_objects.h" @@ -178,7 +182,7 @@ HelicsFederateInfo helicsCreateFederateInfo() static constexpr const char* invalidFedInfoString = "helics Federate info object was not valid"; -static helics::FederateInfo* getFedInfo(HelicsFederateInfo fedInfo, HelicsError* err) +helics::FederateInfo* getFedInfo(HelicsFederateInfo fedInfo, HelicsError* err) { if ((err != nullptr) && (err->error_code != 0)) { return nullptr; @@ -457,188 +461,167 @@ void helicsFederateInfoSetIntegerProperty(HelicsFederateInfo fedInfo, int intege info->setProperty(integerProperty, propertyValue); } +HelicsFederate generateNewHelicsFederateObject(std::shared_ptr fed, helics::FederateType type) +{ + auto fedI = std::make_unique(); + fedI->fedptr = std::move(fed); + fedI->type = type; + fedI->valid = fedValidationIdentifier; + auto* hfed = reinterpret_cast(fedI.get()); + getMasterHolder()->addFed(std::move(fedI)); + return (hfed); +} + /* Creation and destruction of Federates */ HelicsFederate helicsCreateValueFederate(const char* fedName, HelicsFederateInfo fedInfo, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { if (fedInfo == nullptr) { - FedI->fedptr = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); + fed = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); } else { auto* info = getFedInfo(fedInfo, err); if (info == nullptr) { return nullptr; } - FedI->fedptr = std::make_shared(AS_STRING(fedName), *info); + fed = std::make_shared(AS_STRING(fedName), *info); } } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::VALUE; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::VALUE); } HelicsFederate helicsCreateValueFederateFromConfig(const char* configFile, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { - FedI->fedptr = std::make_shared(AS_STRING(configFile)); + fed = std::make_shared(AS_STRING(configFile)); } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::VALUE; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::VALUE); } /* Creation and destruction of Federates */ HelicsFederate helicsCreateMessageFederate(const char* fedName, HelicsFederateInfo fedInfo, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { if (fedInfo == nullptr) { - FedI->fedptr = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); + fed = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); } else { auto* info = getFedInfo(fedInfo, err); if (info == nullptr) { return nullptr; } - FedI->fedptr = std::make_shared(AS_STRING(fedName), *info); + fed = std::make_shared(AS_STRING(fedName), *info); } } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::MESSAGE; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::MESSAGE); } HelicsFederate helicsCreateMessageFederateFromConfig(const char* configFile, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { - FedI->fedptr = std::make_shared(AS_STRING(configFile)); + fed = std::make_shared(AS_STRING(configFile)); } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::MESSAGE; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::MESSAGE); } /* Creation and destruction of Federates */ HelicsFederate helicsCreateCombinationFederate(const char* fedName, HelicsFederateInfo fedInfo, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { if (fedInfo == nullptr) { - FedI->fedptr = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); + fed = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); } else { auto* info = getFedInfo(fedInfo, err); if (info == nullptr) { return nullptr; } - FedI->fedptr = std::make_shared(AS_STRING(fedName), *info); + fed = std::make_shared(AS_STRING(fedName), *info); } } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::COMBINATION; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::COMBINATION); } HelicsFederate helicsCreateCombinationFederateFromConfig(const char* configFile, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { - FedI->fedptr = std::make_shared(AS_STRING(configFile)); + fed = std::make_shared(AS_STRING(configFile)); } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::COMBINATION; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::COMBINATION); } /* Creation and destruction of Federates */ HelicsFederate helicsCreateCallbackFederate(const char* fedName, HelicsFederateInfo fedInfo, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { if (fedInfo == nullptr) { - FedI->fedptr = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); + fed = std::make_shared(AS_STRING(fedName), helics::FederateInfo()); } else { auto* info = getFedInfo(fedInfo, err); if (info == nullptr) { return nullptr; } - FedI->fedptr = std::make_shared(AS_STRING(fedName), *info); + fed = std::make_shared(AS_STRING(fedName), *info); } } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::CALLBACK; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::CALLBACK); } HelicsFederate helicsCreateCallbackFederateFromConfig(const char* configFile, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); - auto FedI = std::make_unique(); + std::shared_ptr fed; try { - FedI->fedptr = std::make_shared(AS_STRING(configFile)); + fed = std::make_shared(AS_STRING(configFile)); } catch (...) { helicsErrorHandler(err); return nullptr; } - FedI->type = helics::FederateType::CALLBACK; - FedI->valid = fedValidationIdentifier; - auto* fed = reinterpret_cast(FedI.get()); - getMasterHolder()->addFed(std::move(FedI)); - return (fed); + return generateNewHelicsFederateObject(std::move(fed), helics::FederateType::CALLBACK); } HelicsFederate helicsFederateClone(HelicsFederate fed, HelicsError* err) @@ -647,14 +630,7 @@ HelicsFederate helicsFederateClone(HelicsFederate fed, HelicsError* err) if (fedObj == nullptr) { return nullptr; } - auto fedClone = std::make_unique(); - fedClone->fedptr = fedObj->fedptr; - - fedClone->type = fedObj->type; - fedClone->valid = fedValidationIdentifier; - auto* fedB = reinterpret_cast(fedClone.get()); - getMasterHolder()->addFed(std::move(fedClone)); - return (fedB); + return generateNewHelicsFederateObject(fedObj->fedptr, fedObj->type); } HelicsFederate helicsGetFederateByName(const char* fedName, HelicsError* err) @@ -678,14 +654,7 @@ HelicsFederate helicsGetFederateByName(const char* fedName, HelicsError* err) } return nullptr; } - auto fedClone = std::make_unique(); - fedClone->fedptr = fed->fedptr; - - fedClone->type = fed->type; - fedClone->valid = fedValidationIdentifier; - auto* fedB = reinterpret_cast(fedClone.get()); - getMasterHolder()->addFed(std::move(fedClone)); - return (fedB); + return generateNewHelicsFederateObject(fed->fedptr, fed->type); } void helicsFederateProtect(const char* fedName, HelicsError* err) @@ -981,7 +950,8 @@ void helicsFederateEnterExecutingMode(HelicsFederate fed, HelicsError* err) } } -static helics::IterationRequest getIterationRequest(HelicsIterationRequest iterate) +namespace { +helics::IterationRequest getIterationRequest(HelicsIterationRequest iterate) { switch (iterate) { case HELICS_ITERATION_REQUEST_NO_ITERATION: @@ -999,7 +969,7 @@ static helics::IterationRequest getIterationRequest(HelicsIterationRequest itera } } -static HelicsIterationResult getIterationStatus(helics::IterationResult iterationState) +HelicsIterationResult getIterationStatus(helics::IterationResult iterationState) { switch (iterationState) { case helics::IterationResult::NEXT_STEP: @@ -1014,7 +984,7 @@ static HelicsIterationResult getIterationStatus(helics::IterationResult iteratio return HELICS_ITERATION_RESULT_HALTED; } } - +} // namespace HelicsIterationResult helicsFederateEnterExecutingModeIterative(HelicsFederate fed, HelicsIterationRequest iterate, HelicsError* err) { auto* fedObj = getFed(fed, err); @@ -1248,10 +1218,12 @@ void helicsFederateProcessCommunications(HelicsFederate fed, HelicsTime period, } } -static HelicsFederateState stateConversion(helics::Federate::Modes mode) +namespace { +HelicsFederateState stateConversion(helics::Federate::Modes mode) { return static_cast(static_cast(static_cast::type>(mode))); } +} // namespace HelicsFederateState helicsFederateGetState(HelicsFederate fed, HelicsError* err) { diff --git a/src/helics/shared_api_library/MessageFederate.h b/src/helics/shared_api_library/MessageFederate.h index 03200bd4e0..288f164ccc 100644 --- a/src/helics/shared_api_library/MessageFederate.h +++ b/src/helics/shared_api_library/MessageFederate.h @@ -157,6 +157,57 @@ HELICS_EXPORT void helicsEndpointSetDefaultDestination(HelicsEndpoint endpoint, */ HELICS_EXPORT const char* helicsEndpointGetDefaultDestination(HelicsEndpoint endpoint); +/** + * Send a message to the targeted destination. + * + * @param endpoint The endpoint to send the data from. + * @param message The string to send. + * @param[in,out] err A pointer to an error object for catching errors. + */ +HELICS_EXPORT void helicsEndpointSendString(HelicsEndpoint endpoint, const char* message, HelicsError* err); + +/** +* Send a message to the specified destination. +* +* @param endpoint The endpoint to send the data from. + +* @param message The string to send. +* +* @param dst The target destination. Use nullptr to send to the default destination. +* @param[in,out] err A pointer to an error object for catching errors. +*/ +HELICS_EXPORT void helicsEndpointSendStringTo(HelicsEndpoint endpoint, const char* message, const char* dst, HelicsError* err); + +/** + * Send a message to the specified destination at a specific time. + * + * @param endpoint The endpoint to send the data from. + * @param message The data to send. + * + * @param dst The target destination. Use nullptr to send to the default destination. + * + * @param time The time the message should be sent. + * + * @param[in,out] err A pointer to an error object for catching errors. + */ + +HELICS_EXPORT void + helicsEndpointSendStringToAt(HelicsEndpoint endpoint, const char* message, const char* dst, HelicsTime time, HelicsError* err); + +/** + * Send a message at a specific time to the targeted destinations. + * + * @param endpoint The endpoint to send the data from. + * + * @param message The data to send. + * + * @param time The time the message should be sent. + * + * @param[in,out] err A pointer to an error object for catching errors. + */ + +HELICS_EXPORT void helicsEndpointSendStringAt(HelicsEndpoint endpoint, const char* message, HelicsTime time, HelicsError* err); + /** * Send a message to the targeted destination. * diff --git a/src/helics/shared_api_library/MessageFederateExport.cpp b/src/helics/shared_api_library/MessageFederateExport.cpp index 4133e3a814..8b10d298ba 100644 --- a/src/helics/shared_api_library/MessageFederateExport.cpp +++ b/src/helics/shared_api_library/MessageFederateExport.cpp @@ -20,14 +20,13 @@ SPDX-License-Identifier: BSD-3-Clause #include #include +namespace { // random integer for validation purposes of endpoints -static constexpr int EndpointValidationIdentifier = 0xB453'94C2; +constexpr int EndpointValidationIdentifier = 0xB453'94C2; -static auto endpointSearch = [](const helics::InterfaceHandle& hnd, const auto& testEndpoint) { - return hnd < testEndpoint->endPtr->getHandle(); -}; +auto endpointSearch = [](const helics::InterfaceHandle& hnd, const auto& testEndpoint) { return hnd < testEndpoint->endPtr->getHandle(); }; -static inline HelicsEndpoint addEndpoint(HelicsFederate fed, std::unique_ptr ept) +inline HelicsEndpoint addEndpoint(HelicsFederate fed, std::unique_ptr ept) { auto* fedObj = reinterpret_cast(fed); ept->valid = EndpointValidationIdentifier; @@ -43,7 +42,7 @@ static inline HelicsEndpoint addEndpoint(HelicsFederate fed, std::unique_ptr(fed); const auto handle = endp.getHandle(); @@ -58,11 +57,11 @@ static HelicsEndpoint findOrCreateEndpoint(HelicsFederate fed, helics::Endpoint& return addEndpoint(fed, std::move(end)); } -static constexpr char nullcstr[] = ""; +constexpr char nullcstr[] = ""; -static constexpr char invalidEndpoint[] = "The given endpoint does not point to a valid object"; +constexpr char invalidEndpoint[] = "The given endpoint does not point to a valid object"; -static helics::EndpointObject* verifyEndpoint(HelicsEndpoint ept, HelicsError* err) +helics::EndpointObject* verifyEndpoint(HelicsEndpoint ept, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); auto* endObj = reinterpret_cast(ept); @@ -72,6 +71,7 @@ static helics::EndpointObject* verifyEndpoint(HelicsEndpoint ept, HelicsError* e } return endObj; } +} // namespace HelicsEndpoint helicsFederateRegisterEndpoint(HelicsFederate fed, const char* name, const char* type, HelicsError* err) { @@ -166,12 +166,12 @@ HelicsEndpoint helicsFederateGetEndpoint(HelicsFederate fed, const char* name, H } CHECK_NULL_STRING(name, nullptr); try { - auto& id = fedObj->getEndpoint(name); - if (!id.isValid()) { + auto& ept = fedObj->getEndpoint(name); + if (!ept.isValid()) { assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidEndName); return nullptr; } - return findOrCreateEndpoint(fed, id); + return findOrCreateEndpoint(fed, ept); } // LCOV_EXCL_START catch (...) { @@ -188,12 +188,12 @@ HelicsEndpoint helicsFederateGetEndpointByIndex(HelicsFederate fed, int index, H return nullptr; } try { - auto& id = fedObj->getEndpoint(index); - if (!id.isValid()) { + auto& ept = fedObj->getEndpoint(index); + if (!ept.isValid()) { assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidEndIndex); return nullptr; } - return findOrCreateEndpoint(fed, id); + return findOrCreateEndpoint(fed, ept); } // LCOV_EXCL_START catch (...) { @@ -239,6 +239,66 @@ const char* helicsEndpointGetDefaultDestination(HelicsEndpoint endpoint) return str.c_str(); } +void helicsEndpointSendString(HelicsEndpoint endpoint, const char* message, HelicsError* err) +{ + auto* endObj = verifyEndpoint(endpoint, err); + if (endObj == nullptr) { + return; + } + try { + if (message == nullptr) { + endObj->endPtr->send(gHelicsEmptyStr); + } else { + endObj->endPtr->send(message); + } + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsEndpointSendStringTo(HelicsEndpoint endpoint, const char* message, const char* dest, HelicsError* err) +{ + auto* endObj = verifyEndpoint(endpoint, err); + if (endObj == nullptr) { + return; + } + try { + endObj->endPtr->sendTo(AS_STRING_VIEW(message), AS_STRING_VIEW(dest)); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsEndpointSendStringAt(HelicsEndpoint endpoint, const char* message, HelicsTime time, HelicsError* err) +{ + auto* endObj = verifyEndpoint(endpoint, err); + if (endObj == nullptr) { + return; + } + try { + endObj->endPtr->sendAt(AS_STRING_VIEW(message), time); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsEndpointSendStringToAt(HelicsEndpoint endpoint, const char* message, const char* dest, HelicsTime time, HelicsError* err) +{ + auto* endObj = verifyEndpoint(endpoint, err); + if (endObj == nullptr) { + return; + } + try { + endObj->endPtr->sendToAt(AS_STRING_VIEW(message), AS_STRING_VIEW(dest), time); + } + catch (...) { + helicsErrorHandler(err); + } +} + void helicsEndpointSendBytes(HelicsEndpoint endpoint, const void* data, int inputDataLength, HelicsError* err) { auto* endObj = verifyEndpoint(endpoint, err); @@ -417,7 +477,7 @@ Message* MessageHolder::addMessage(std::unique_ptr& mess) if (!mess) { return nullptr; } - Message* m = mess.get(); + Message* message = mess.get(); mess->backReference = static_cast(this); if (!freeMessageSlots.empty()) { auto index = freeMessageSlots.back(); @@ -428,27 +488,27 @@ Message* MessageHolder::addMessage(std::unique_ptr& mess) mess->counter = static_cast(messages.size()); messages.push_back(std::move(mess)); } - return m; + return message; } Message* MessageHolder::newMessage() { - Message* m{nullptr}; + Message* message{nullptr}; if (!freeMessageSlots.empty()) { auto index = freeMessageSlots.back(); freeMessageSlots.pop_back(); messages[index] = std::make_unique(); - m = messages[index].get(); - m->counter = index; + message = messages[index].get(); + message->counter = index; } else { messages.push_back(std::make_unique()); - m = messages.back().get(); - m->counter = static_cast(messages.size()) - 1; + message = messages.back().get(); + message->counter = static_cast(messages.size()) - 1; } - m->messageValidation = messageKeyCode; - m->backReference = static_cast(this); - return m; + message->messageValidation = messageKeyCode; + message->backReference = static_cast(this); + return message; } std::unique_ptr MessageHolder::extractMessage(int index) @@ -479,10 +539,10 @@ void MessageHolder::freeMessage(int index) void MessageHolder::clear() { freeMessageSlots.clear(); - for (auto& m : messages) { - if (m) { - m->backReference = nullptr; - m->messageValidation = 0; + for (auto& message : messages) { + if (message) { + message->backReference = nullptr; + message->messageValidation = 0; } } messages.clear(); diff --git a/src/helics/shared_api_library/ValueFederateExport.cpp b/src/helics/shared_api_library/ValueFederateExport.cpp index 0702bafde5..8d117129bc 100644 --- a/src/helics/shared_api_library/ValueFederateExport.cpp +++ b/src/helics/shared_api_library/ValueFederateExport.cpp @@ -19,17 +19,18 @@ SPDX-License-Identifier: BSD-3-Clause #include #include +namespace { /** random integer for validation purposes of inputs */ -static constexpr int InputValidationIdentifier = 0x3456'E052; +constexpr int InputValidationIdentifier = 0x3456'E052; /** random integer for validation purposes of publications */ -static constexpr int PublicationValidationIdentifier = 0x97B1'00A5; +constexpr int PublicationValidationIdentifier = 0x97B1'00A5; -static constexpr char invalidInputString[] = "The given input object does not point to a valid object"; +constexpr char invalidInputString[] = "The given input object does not point to a valid object"; -static constexpr char invalidPublicationString[] = "The given publication object does not point to a valid object"; +constexpr char invalidPublicationString[] = "The given publication object does not point to a valid object"; -static helics::InputObject* verifyInput(HelicsInput inp, HelicsError* err) +helics::InputObject* verifyInput(HelicsInput inp, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); if (inp == nullptr) { @@ -44,7 +45,7 @@ static helics::InputObject* verifyInput(HelicsInput inp, HelicsError* err) return inpObj; } -static helics::PublicationObject* verifyPublication(HelicsPublication pub, HelicsError* err) +helics::PublicationObject* verifyPublication(HelicsPublication pub, HelicsError* err) { HELICS_ERROR_CHECK(err, nullptr); if (pub == nullptr) { @@ -59,9 +60,9 @@ static helics::PublicationObject* verifyPublication(HelicsPublication pub, Helic return pubObj; } -static auto inputSearch = [](const helics::InterfaceHandle& hnd, const auto& testInput) { return hnd < testInput->inputPtr->getHandle(); }; +auto inputSearch = [](const helics::InterfaceHandle& hnd, const auto& testInput) { return hnd < testInput->inputPtr->getHandle(); }; -static inline HelicsInput addInput(HelicsFederate fed, std::unique_ptr inp) +inline HelicsInput addInput(HelicsFederate fed, std::unique_ptr inp) { auto* fedObj = reinterpret_cast(fed); inp->valid = InputValidationIdentifier; @@ -75,7 +76,7 @@ static inline HelicsInput addInput(HelicsFederate fed, std::unique_ptr(fed); const auto handle = input.getHandle(); @@ -90,9 +91,9 @@ static HelicsInput findOrCreateInput(HelicsFederate fed, helics::Input& input) return addInput(fed, std::move(inp)); } -static auto pubSearch = [](const helics::InterfaceHandle& hnd, const auto& testPub) { return hnd < testPub->pubPtr->getHandle(); }; +auto pubSearch = [](const helics::InterfaceHandle& hnd, const auto& testPub) { return hnd < testPub->pubPtr->getHandle(); }; -static inline HelicsPublication addPublication(HelicsFederate fed, std::unique_ptr pub) +HelicsPublication addPublication(HelicsFederate fed, std::unique_ptr pub) { auto* fedObj = reinterpret_cast(fed); pub->valid = PublicationValidationIdentifier; @@ -107,7 +108,7 @@ static inline HelicsPublication addPublication(HelicsFederate fed, std::unique_p return hpub; } -static HelicsPublication findOrCreatePublication(HelicsFederate fed, helics::Publication& pub) +HelicsPublication findOrCreatePublication(HelicsFederate fed, helics::Publication& pub) { auto* fedObj = reinterpret_cast(fed); const auto handle = pub.getHandle(); @@ -121,7 +122,7 @@ static HelicsPublication findOrCreatePublication(HelicsFederate fed, helics::Pub pubObj->fedptr = getValueFedSharedPtr(fed, nullptr); return addPublication(fed, std::move(pubObj)); } - +} // namespace /* input/pub registration */ HelicsInput helicsFederateRegisterSubscription(HelicsFederate fed, const char* key, const char* units, HelicsError* err) { @@ -434,12 +435,12 @@ HelicsInput helicsFederateGetInput(HelicsFederate fed, const char* key, HelicsEr } CHECK_NULL_STRING(key, nullptr); try { - auto& id = fedObj->getInput(key); - if (!id.isValid()) { + auto& input = fedObj->getInput(key); + if (!input.isValid()) { assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidInputName); return nullptr; } - return findOrCreateInput(fed, id); + return findOrCreateInput(fed, input); } // LCOV_EXCL_START catch (...) { @@ -456,12 +457,12 @@ HelicsInput helicsFederateGetInputByIndex(HelicsFederate fed, int index, HelicsE return nullptr; } try { - auto& id = fedObj->getInput(index); - if (!id.isValid()) { + auto& input = fedObj->getInput(index); + if (!input.isValid()) { assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidInputIndex); return nullptr; } - return findOrCreateInput(fed, id); + return findOrCreateInput(fed, input); } // LCOV_EXCL_START catch (...) { @@ -486,12 +487,12 @@ HelicsInput helicsFederateGetInputByTarget(HelicsFederate fed, const char* targe } CHECK_NULL_STRING(target, nullptr); try { - auto& id = fedObj->getInputByTarget(target); - if (!id.isValid()) { + auto& input = fedObj->getInputByTarget(target); + if (!input.isValid()) { assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidTargetKey); return nullptr; } - return findOrCreateInput(fed, id); + return findOrCreateInput(fed, input); } // LCOV_EXCL_START catch (...) { @@ -512,6 +513,7 @@ void helicsFederateClearUpdates(HelicsFederate fed) } // LCOV_EXCL_START catch (...) { + ; } // LCOV_EXCL_STOP } @@ -594,7 +596,7 @@ void helicsPublicationPublishTime(HelicsPublication pub, HelicsTime val, HelicsE return; } try { - helics::Time tval(val); + const helics::Time tval(val); pubObj->pubPtr->publish(tval); } catch (...) { @@ -769,8 +771,8 @@ HelicsDataBuffer helicsInputGetDataBuffer(HelicsInput inp, HelicsError* err) if (inpObj == nullptr) { return (nullptr); } - helics::data_view dv = inpObj->inputPtr->getBytes(); - auto* ptr = new helics::SmallBuffer(dv.string_view()); + const helics::data_view bytes = inpObj->inputPtr->getBytes(); + auto* ptr = new helics::SmallBuffer(bytes.string_view()); return createAPIDataBuffer(*ptr); } @@ -787,15 +789,15 @@ void helicsInputGetBytes(HelicsInput inp, void* data, int maxDatalen, int* actua return; } try { - auto dv = inpObj->inputPtr->getBytes(); - if (maxDatalen > static_cast(dv.size())) { - memcpy(data, dv.data(), dv.size()); + auto bytes = inpObj->inputPtr->getBytes(); + if (maxDatalen > static_cast(bytes.size())) { + memcpy(data, bytes.data(), bytes.size()); if (actualSize != nullptr) { - *actualSize = static_cast(dv.size()); + *actualSize = static_cast(bytes.size()); } return; } - memcpy(data, dv.data(), maxDatalen); + memcpy(data, bytes.data(), maxDatalen); if (actualSize != nullptr) { *actualSize = maxDatalen; } @@ -822,7 +824,7 @@ void helicsInputGetString(HelicsInput inp, char* outputString, int maxStringLen, return; } try { - int length = inpObj->inputPtr->getValue(outputString, maxStringLen); + const int length = inpObj->inputPtr->getValue(outputString, maxStringLen); if (actualLength != nullptr) { // for initialization *actualLength = length; } @@ -856,7 +858,7 @@ HelicsBool helicsInputGetBoolean(HelicsInput inp, HelicsError* err) return HELICS_FALSE; } try { - bool boolval = inpObj->inputPtr->getValue(); + const bool boolval = inpObj->inputPtr->getValue(); return (boolval) ? HELICS_TRUE : HELICS_FALSE; } // LCOV_EXCL_START @@ -871,14 +873,14 @@ double helicsInputGetDouble(HelicsInput inp, HelicsError* err) { auto* inpObj = verifyInput(inp, err); if (inpObj == nullptr) { - return HELICS_TIME_INVALID; + return HELICS_INVALID_DOUBLE; } try { return inpObj->inputPtr->getValue(); } catch (...) { helicsErrorHandler(err); - return HELICS_TIME_INVALID; + return HELICS_INVALID_DOUBLE; } } @@ -889,8 +891,8 @@ HelicsTime helicsInputGetTime(HelicsInput inp, HelicsError* err) return HELICS_TIME_INVALID; } try { - auto T = inpObj->inputPtr->getValue(); - return static_cast(T); + auto time = inpObj->inputPtr->getValue(); + return static_cast(time); } // LCOV_EXCL_START catch (...) { @@ -1007,7 +1009,7 @@ void helicsInputGetVector(HelicsInput inp, double data[], int maxlen, int* actua return; } try { - int length = inpObj->inputPtr->getValue(data, maxlen); + const int length = inpObj->inputPtr->getValue(data, maxlen); if (actualSize != nullptr) { *actualSize = length; } @@ -1034,7 +1036,7 @@ void helicsInputGetComplexVector(HelicsInput inp, double data[], int maxlen, int return; } try { - int length = inpObj->inputPtr->getComplexValue(data, maxlen); + const int length = inpObj->inputPtr->getComplexValue(data, maxlen); if (actualSize != nullptr) { *actualSize = length; } @@ -1057,10 +1059,10 @@ void helicsInputGetNamedPoint(HelicsInput inp, char* outputString, int maxString } try { - helics::NamedPoint np = inpObj->inputPtr->getValue(); + helics::NamedPoint npoint = inpObj->inputPtr->getValue(); if (outputString != nullptr && maxStringLen > 0) { - int length = std::min(static_cast(np.name.size()), maxStringLen); - memcpy(outputString, np.name.data(), length); + const int length = std::min(static_cast(npoint.name.size()), maxStringLen); + memcpy(outputString, npoint.name.data(), length); if (length == maxStringLen) { outputString[maxStringLen - 1] = '\0'; @@ -1075,7 +1077,7 @@ void helicsInputGetNamedPoint(HelicsInput inp, char* outputString, int maxString } } if (val != nullptr) { - *val = np.value; + *val = npoint.value; } return; @@ -1157,7 +1159,7 @@ void helicsInputSetDefaultTime(HelicsInput inp, HelicsTime val, HelicsError* err return; } - helics::Time tval(val); + const helics::Time tval(val); inpObj->inputPtr->setDefault(tval); } @@ -1210,12 +1212,12 @@ void helicsInputSetDefaultComplexVector(HelicsInput inp, const double* vectorInp if ((vectorInput == nullptr) || (vectorLength <= 0)) { inpObj->inputPtr->setDefault(std::vector>{}); } else { - std::vector> CV; - CV.reserve(vectorLength); - for (int ii = 0; ii < vectorLength; ++ii) { - CV.emplace_back(vectorInput[2 * ii], vectorInput[2 * ii + 1]); + std::vector> cvec; + cvec.reserve(vectorLength); + for (std::ptrdiff_t ii = 0; ii < vectorLength; ++ii) { + cvec.emplace_back(vectorInput[2 * ii], vectorInput[2 * ii + 1]); } - inpObj->inputPtr->setDefault(std::move(CV)); + inpObj->inputPtr->setDefault(std::move(cvec)); } } // LCOV_EXCL_START @@ -1660,6 +1662,7 @@ void helicsInputClearUpdate(HelicsInput inp) } // LCOV_EXCL_START catch (...) { + ; } // LCOV_EXCL_STOP } diff --git a/src/helics/shared_api_library/api-data.h b/src/helics/shared_api_library/api-data.h index 5041a42ae9..29e7501e04 100644 --- a/src/helics/shared_api_library/api-data.h +++ b/src/helics/shared_api_library/api-data.h @@ -64,6 +64,12 @@ typedef void* HelicsBroker; // typedef void* helics_federate; typedef void* HelicsFederate; +/** + * opaque object representing a helics app + */ +// typedef void* helics_federate; +typedef void* HelicsApp; + /** * opaque object representing a filter info object structure */ diff --git a/src/helics/shared_api_library/backup/helics/helics.h b/src/helics/shared_api_library/backup/helics/helics.h index 9439aa28ef..bf4527928a 100644 --- a/src/helics/shared_api_library/backup/helics/helics.h +++ b/src/helics/shared_api_library/backup/helics/helics.h @@ -460,6 +460,8 @@ typedef enum { /* NOLINT */ #define HELICS_BIG_NUMBER 9223372036.854774 const double cHelicsBigNumber = HELICS_BIG_NUMBER; +#define HELICS_INVALID_DOUBLE -1E49 + /** * @file * @brief Data structures for the C api @@ -509,6 +511,12 @@ typedef void* HelicsBroker; // typedef void* helics_federate; typedef void* HelicsFederate; +/** + * opaque object representing a helics app + */ +// typedef void* helics_federate; +typedef void* HelicsApp; + /** * opaque object representing a filter info object structure */ @@ -2607,6 +2615,90 @@ HELICS_EXPORT void helicsQueryFree(HelicsQuery query); */ HELICS_EXPORT void helicsCleanupLibrary(void); +/** +* Create a helics app object +* +* @details create a helics App object +* +* @param appName A string with the name of the app, can be NULL or an empty string to pull the default name from fedInfo or the config file. +* @param appType the type of app to create +* @param configFile configuration file or string to pass into the app, can be NULL or empty +* @param fedInfo the federate information to pass into the app, can be NULL +* @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + +* +* @return An opaque value app object nullptr if the object creation failed. +*/ +HELICS_EXPORT HelicsApp + helicsCreateApp(const char* appName, const char* appType, const char* configFile, HelicsFederateInfo fedInfo, HelicsError* err); + +/** run the App +* @details execute the app to completion +* @param app the app to execute +* @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. +* +* @return An opaque value federate object that can be used in any of the federate methods, not recommended to use this object to advance +time, the app will not likely function normally, other query, or information calls, or modification calls on the federate are fine. +*/ +HELICS_EXPORT HelicsFederate helicsAppGetFederate(HelicsApp app, HelicsError* err); + +/** +* Create a helics app object +* +* @details create a helics App object +* +* @param appName A string with the name of the app, can be NULL or an empty string to pull the default name from fedInfo or the config file. +* @param appType the type of app to create +* @param configFile configuration file or string to pass into the app, can be NULL or empty +* @param fedInfo the federate information to pass into the app, can be NULL +* @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + +* +* @return An opaque value app object nullptr if the object creation failed. +*/ +HELICS_EXPORT void helicsAppLoadFile(HelicsApp app, const char* configFile, HelicsError* err); + +/** initialize the App federate + * @details generate all the interfaces and load data for the application + * @param app the app to initialize + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppInitialize(HelicsApp app, HelicsError* err); + +/** run the App + * @details execute the app to completion + * @param app the app to execute + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppRun(HelicsApp app, HelicsError* err); + +/** run and app to a specified stop time + * @details it is possible to call this method repeatedly with different times + * @param app the app to run + * @param stopTime the desired stop time + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppRunTo(HelicsApp app, HelicsTime stopTime, HelicsError* err); + +/** finalize the app + * @param app the app to execute + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppFinalize(HelicsApp app, HelicsError* err); + +/** finalize the app + * @param app the app to free + */ +HELICS_EXPORT void helicsAppFree(HelicsApp app); + +/** disconnect and free an App + * @param app the app to destroy + */ +HELICS_EXPORT void helicsAppDestroy(HelicsApp app); + +/** check if the App is active and ready to run*/ +HELICS_EXPORT HelicsBool helicsAppIsActive(HelicsApp app); + /** * input/publication registration */ @@ -3809,6 +3901,57 @@ HELICS_EXPORT void helicsEndpointSetDefaultDestination(HelicsEndpoint endpoint, */ HELICS_EXPORT const char* helicsEndpointGetDefaultDestination(HelicsEndpoint endpoint); +/** + * Send a message to the targeted destination. + * + * @param endpoint The endpoint to send the data from. + * @param message The string to send. + * @param[in,out] err A pointer to an error object for catching errors. + */ +HELICS_EXPORT void helicsEndpointSendString(HelicsEndpoint endpoint, const char* message, HelicsError* err); + +/** +* Send a message to the specified destination. +* +* @param endpoint The endpoint to send the data from. + +* @param message The string to send. +* +* @param dst The target destination. Use nullptr to send to the default destination. +* @param[in,out] err A pointer to an error object for catching errors. +*/ +HELICS_EXPORT void helicsEndpointSendStringTo(HelicsEndpoint endpoint, const char* message, const char* dst, HelicsError* err); + +/** + * Send a message to the specified destination at a specific time. + * + * @param endpoint The endpoint to send the data from. + * @param message The data to send. + * + * @param dst The target destination. Use nullptr to send to the default destination. + * + * @param time The time the message should be sent. + * + * @param[in,out] err A pointer to an error object for catching errors. + */ + +HELICS_EXPORT void + helicsEndpointSendStringToAt(HelicsEndpoint endpoint, const char* message, const char* dst, HelicsTime time, HelicsError* err); + +/** + * Send a message at a specific time to the targeted destinations + * + * @param endpoint The endpoint to send the data from. + * + * @param message The data to send. + * + * @param time The time the message should be sent. + * + * @param[in,out] err A pointer to an error object for catching errors. + */ + +HELICS_EXPORT void helicsEndpointSendStringAt(HelicsEndpoint endpoint, const char* message, HelicsTime time, HelicsError* err); + /** * Send a message to the targeted destination. * diff --git a/src/helics/shared_api_library/backup/helics/helics_api.h b/src/helics/shared_api_library/backup/helics/helics_api.h index 7ab1171d11..53ce1ba35e 100644 --- a/src/helics/shared_api_library/backup/helics/helics_api.h +++ b/src/helics/shared_api_library/backup/helics/helics_api.h @@ -217,6 +217,8 @@ typedef enum { #define HELICS_BIG_NUMBER 9223372036.854774 const double cHelicsBigNumber = HELICS_BIG_NUMBER; + +#define HELICS_INVALID_DOUBLE -1E49 typedef void* HelicsInput; typedef void* HelicsPublication; @@ -233,6 +235,8 @@ typedef void* HelicsBroker; typedef void* HelicsFederate; +typedef void* HelicsApp; + typedef void* HelicsFederateInfo; typedef void* HelicsQuery; @@ -505,6 +509,16 @@ void helicsQuerySetQueryString(HelicsQuery query, const char* queryString, Helic void helicsQuerySetOrdering(HelicsQuery query, int32_t mode, HelicsError* err); void helicsQueryFree(HelicsQuery query); void helicsCleanupLibrary(void); +HelicsApp helicsCreateApp(const char* appName, const char* appType, const char* configFile, HelicsFederateInfo fedInfo, HelicsError* err); +HelicsFederate helicsAppGetFederate(HelicsApp app, HelicsError* err); +void helicsAppLoadFile(HelicsApp app, const char* configFile, HelicsError* err); +void helicsAppInitialize(HelicsApp app, HelicsError* err); +void helicsAppRun(HelicsApp app, HelicsError* err); +void helicsAppRunTo(HelicsApp app, HelicsTime stopTime, HelicsError* err); +void helicsAppFinalize(HelicsApp app, HelicsError* err); +void helicsAppFree(HelicsApp app); +void helicsAppDestroy(HelicsApp app); +HelicsBool helicsAppIsActive(HelicsApp app); HelicsInput helicsFederateRegisterSubscription(HelicsFederate fed, const char* key, const char* units, HelicsError* err); HelicsPublication helicsFederateRegisterPublication(HelicsFederate fed, const char* key, HelicsDataTypes type, const char* units, HelicsError* err); @@ -615,6 +629,10 @@ HelicsEndpoint helicsFederateGetEndpointByIndex(HelicsFederate fed, int index, H HelicsBool helicsEndpointIsValid(HelicsEndpoint endpoint); void helicsEndpointSetDefaultDestination(HelicsEndpoint endpoint, const char* dst, HelicsError* err); const char* helicsEndpointGetDefaultDestination(HelicsEndpoint endpoint); +void helicsEndpointSendString(HelicsEndpoint endpoint, const char* message, HelicsError* err); +void helicsEndpointSendStringTo(HelicsEndpoint endpoint, const char* message, const char* dst, HelicsError* err); +void helicsEndpointSendStringToAt(HelicsEndpoint endpoint, const char* message, const char* dst, HelicsTime time, HelicsError* err); +void helicsEndpointSendStringAt(HelicsEndpoint endpoint, const char* message, HelicsTime time, HelicsError* err); void helicsEndpointSendBytes(HelicsEndpoint endpoint, const void* data, int inputDataLength, HelicsError* err); void helicsEndpointSendBytesTo(HelicsEndpoint endpoint, const void* data, int inputDataLength, const char* dst, HelicsError* err); void helicsEndpointSendBytesToAt(HelicsEndpoint endpoint, diff --git a/src/helics/shared_api_library/export_mac.txt b/src/helics/shared_api_library/export_mac.txt index f90ddb7284..e4fc4e0b73 100644 --- a/src/helics/shared_api_library/export_mac.txt +++ b/src/helics/shared_api_library/export_mac.txt @@ -1,7 +1,10 @@ *helicsBroker* *helicsFederate* +*helicsApp* *helicsCallbackFederate* *helicsCore* +*helicsWrapData* +*helicsData* *helicsPublication* *helicsInput* *helicsEndpoint* diff --git a/src/helics/shared_api_library/helicsApps.h b/src/helics/shared_api_library/helicsApps.h new file mode 100644 index 0000000000..82774ccf1c --- /dev/null +++ b/src/helics/shared_api_library/helicsApps.h @@ -0,0 +1,113 @@ +/* +Copyright (c) 2017-2024, +Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable Energy, LLC. See the top-level NOTICE for +additional details. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +*/ + +/** + * @file + * @brief Functions related to using helics apps + */ + +#ifndef HELICS_APISHARED_APP_FUNCTIONS_H_ +#define HELICS_APISHARED_APP_FUNCTIONS_H_ + +#include "helicsCore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Create a HelicsApp object. +* +* @details Create a HelicsApp object. +* +* @param appName A string with the name of the app, can be NULL or an empty string to pull the default name from fedInfo or the config file. +* @param appType The type of app to create. +* @param configFile Configuration file or string to pass into the app, can be NULL or empty. +* @param fedInfo The federate information to pass into the app, can be NULL. +* @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + +* +* @return An opaque value app object, or nullptr if the object creation failed. +*/ +HELICS_EXPORT HelicsApp + helicsCreateApp(const char* appName, const char* appType, const char* configFile, HelicsFederateInfo fedInfo, HelicsError* err); + +/** Run the HelicsApp. +* @details Execute the HelicsApp to completion +* @param app The app to execute. +* @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. +* +* @return An opaque value federate object that can be used in any of the federate methods, not recommended to use this object to advance +time, the app will not likely function normally; other query, information calls, or modification calls on the federate are fine. +*/ +HELICS_EXPORT HelicsFederate helicsAppGetFederate(HelicsApp app, HelicsError* err); + +/** + * Create a HelicsApp object. + * + * @details Create a HelicsApp object. + * + * @param appName A string with the name of the app, can be NULL or an empty string to pull the default name from fedInfo or the config + * file. + * @param appType The type of app to create. + * @param configFile Configuration file or string to pass into the app, can be NULL or empty. + * @param fedInfo The federate information to pass into the app, can be NULL. + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + * + * @return An opaque value app object, or nullptr if the object creation failed. + */ +HELICS_EXPORT void helicsAppLoadFile(HelicsApp app, const char* configFile, HelicsError* err); + +/** Initialize the HelicsApp federate. + * @details Generate all the interfaces and load data for the application. + * @param app The app to initialize. + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppInitialize(HelicsApp app, HelicsError* err); + +/** Run the HelicsApp. + * @details Execute the app to completion. + * @param app The app to execute. + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppRun(HelicsApp app, HelicsError* err); + +/** Run a HelicsApp to a specified stop time. + * @details It is possible to call this method repeatedly with different times. + * @param app The app to run. + * @param stopTime The desired stop time. + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppRunTo(HelicsApp app, HelicsTime stopTime, HelicsError* err); + +/** Finalize the HelicsApp. + * @param app The app to finalize. + * @param[in,out] err An error object that will contain an error code and string if any error occurred during the execution of the function. + */ +HELICS_EXPORT void helicsAppFinalize(HelicsApp app, HelicsError* err); + +/** Free the HelicsApp object. + * @param app The app to free. + */ +HELICS_EXPORT void helicsAppFree(HelicsApp app); + +/** Disconnect and free a HelicsApp. + * @param app The app to destroy. + */ +HELICS_EXPORT void helicsAppDestroy(HelicsApp app); + +/** Check if the HelicsApp is active and ready to run. + * @param app The app to check. + * @return True if the app is active, otherwise false. + */ +HELICS_EXPORT HelicsBool helicsAppIsActive(HelicsApp app); + +#ifdef __cplusplus +} /* end of extern "C" { */ +#endif + +#endif diff --git a/src/helics/shared_api_library/helicsAppsExport.cpp b/src/helics/shared_api_library/helicsAppsExport.cpp new file mode 100644 index 0000000000..b490804e7a --- /dev/null +++ b/src/helics/shared_api_library/helicsAppsExport.cpp @@ -0,0 +1,252 @@ +/* +Copyright (c) 2017-2024, +Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable Energy, LLC. See the top-level NOTICE for +additional details. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "../common/configFileHelpers.hpp" +#include "../core/CoreFactory.hpp" +#include "../core/core-exceptions.hpp" +#include "../core/coreTypeOperations.hpp" +#include "../helics.hpp" +#include "api-data.h" +#include "gmlc/concurrency/TripWire.hpp" +#include "helics/helics_apps.hpp" +#include "helicsApps.h" +#include "internal/api_objects.h" + +#include +#include + +namespace helics { + +/** this is a random identifier put in place when the federate or core or broker gets created*/ +static constexpr int appValidationIdentifier = 0x7A8F'1C4D; + +static constexpr const char* invalidAppString = "app object is not valid"; + +AppObject* getAppObject(HelicsApp app, HelicsError* err) noexcept +{ + HELICS_ERROR_CHECK(err, nullptr); + if (app == nullptr) { + assignError(err, HELICS_ERROR_INVALID_OBJECT, invalidAppString); + return nullptr; + } + auto* appObj = reinterpret_cast(app); + if (appObj->valid == appValidationIdentifier) { + return appObj; + } + assignError(err, HELICS_ERROR_INVALID_OBJECT, invalidAppString); + return nullptr; +} + +} // namespace helics + +helics::apps::App* getApp(HelicsApp app, HelicsError* err) +{ + auto* appObj = helics::getAppObject(app, err); + if (appObj == nullptr) { + return nullptr; + } + return appObj->app.get(); +} + +std::shared_ptr getAppSharedPtr(HelicsApp app, HelicsError* err) +{ + auto* appObj = helics::getAppObject(app, err); + if (appObj == nullptr) { + return nullptr; + } + return appObj->app; +} + +namespace { +std::shared_ptr buildApp(std::string_view type, std::string_view appName, helics::FederateInfo& fedInfo) +{ + if (type == "player") { + return std::make_shared(appName, fedInfo); + } + if (type == "recorder") { + return std::make_shared(appName, fedInfo); + } + if (type == "connector") { + return std::make_shared(appName, fedInfo); + } + if (type == "echo") { + return std::make_shared(appName, fedInfo); + } + if (type == "clone") { + return std::make_shared(appName, fedInfo); + } + if (type == "probe") { + return std::make_shared(appName, fedInfo); + } + if (type == "tracer") { + return std::make_shared(appName, fedInfo); + } + if (type == "source") { + return std::make_shared(appName, fedInfo); + } + return nullptr; +} +} // namespace +HelicsApp helicsCreateApp(const char* appName, const char* appType, const char* configFile, HelicsFederateInfo fedInfo, HelicsError* err) +{ + static constexpr const char* invalidAppTypeString = + "app type must be one of 'connector', 'source','recorder','player','echo','clone','probe','tracer'"; + if ((err != nullptr) && (err->error_code != 0)) { + return nullptr; + } + + try { + auto cstring = AS_STRING(configFile); + auto app = std::make_unique(); + app->valid = helics::appValidationIdentifier; + auto nstring = AS_STRING_VIEW(appName); + if (appType == nullptr) { + assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidAppTypeString); + return nullptr; + } + + const std::string_view appTypeName(appType); + bool loadFile = !cstring.empty(); + if (fedInfo == nullptr && helics::fileops::getConfigType(cstring) != helics::fileops::ConfigType::NONE) { + helics::FederateInfo newFedInfo = helics::loadFederateInfo(cstring); + app->app = buildApp(appTypeName, nstring, newFedInfo); + loadFile = false; + } else { + auto* info = getFedInfo(fedInfo, err); + if (info == nullptr) { + return nullptr; + } + app->app = buildApp(appTypeName, nstring, *info); + } + + if (!app->app) { + assignError(err, HELICS_ERROR_INVALID_ARGUMENT, invalidAppTypeString); + return nullptr; + } + if (loadFile && !cstring.empty()) { + app->app->loadFile(cstring); + } + auto* retapp = reinterpret_cast(app.get()); + getMasterHolder()->addApp(std::move(app)); + return retapp; + } + catch (...) { + helicsErrorHandler(err); + return nullptr; + } +} + +HelicsFederate helicsAppGetFederate(HelicsApp app, HelicsError* err) +{ + auto* happ = getApp(app, err); + if (happ == nullptr) { + return nullptr; + } + try { + return generateNewHelicsFederateObject(happ->getUnderlyingFederatePointer(), helics::FederateType::COMBINATION); + } + catch (...) { + helicsErrorHandler(err); + return nullptr; + } +} + +void helicsAppLoadFile(HelicsApp app, const char* configFile, HelicsError* err) +{ + auto* happ = getApp(app, err); + if (happ == nullptr) { + return; + } + try { + happ->loadFile(AS_STRING(configFile)); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsAppInitialize(HelicsApp app, HelicsError* err) +{ + auto* happ = getApp(app, err); + if (happ == nullptr) { + return; + } + try { + happ->initialize(); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsAppRun(HelicsApp app, HelicsError* err) +{ + auto* happ = getApp(app, err); + if (happ == nullptr) { + return; + } + try { + happ->run(); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsAppRunTo(HelicsApp app, HelicsTime stopTime, HelicsError* err) +{ + auto* happ = getApp(app, err); + if (happ == nullptr) { + return; + } + try { + happ->runTo(stopTime); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsAppFinalize(HelicsApp app, HelicsError* err) +{ + auto* happ = getApp(app, err); + if (happ == nullptr) { + return; + } + try { + happ->finalize(); + } + catch (...) { + helicsErrorHandler(err); + } +} + +void helicsAppFree(HelicsApp app) +{ + auto* appObj = helics::getAppObject(app, nullptr); + if (appObj != nullptr) { + appObj->valid = 0; + getMasterHolder()->clearApp(appObj->index); + } + + helics::CoreFactory::cleanUpCores(); +} + +void helicsAppDestroy(HelicsApp app) +{ + helicsAppFinalize(app, nullptr); + helicsAppFree(app); +} + +HelicsBool helicsAppIsActive(HelicsApp app) +{ + auto* happ = getApp(app, nullptr); + if (happ == nullptr) { + return HELICS_FALSE; + } + return (happ->isActive() ? HELICS_TRUE : HELICS_FALSE); +} diff --git a/src/helics/shared_api_library/helicsAppsExportNull.cpp b/src/helics/shared_api_library/helicsAppsExportNull.cpp new file mode 100644 index 0000000000..89375b9007 --- /dev/null +++ b/src/helics/shared_api_library/helicsAppsExportNull.cpp @@ -0,0 +1,71 @@ +/* +Copyright (c) 2017-2024, +Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable Energy, LLC. See the top-level NOTICE for +additional details. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "helicsApps.h" +#include "internal/api_objects.h" + +static constexpr const char* invalidAppString = "app object is not valid"; +static constexpr const char* notLoadedString = + "helics apps not compiled into library, enable apps when building" helics::apps::App * getApp(HelicsApp app, HelicsError* err) +{ + HELICS_ERROR_CHECK(err, nullptr); + if (app == nullptr) { + assignError(err, HELICS_ERROR_INVALID_OBJECT, invalidAppString); + } else { + assignError(err, HELICS_ERROR_OTHER, notLoadedString); + } + return nullptr; +} + +static constexpr char nullcstr[] = ""; + +HelicsApp helicsCreateApp(const char* /*appName*/, + const char* /*appType*/, + const char* /*configFile*/, + HelicsFederateInfo /*fedInfo*/, + HelicsError* err) +{ + HELICS_ERROR_CHECK(err, nullptr); + assignError(err, HELICS_ERROR_OTHER, notLoadedString); + return nullptr; +} + +HelicsFederate helicsAppGetFederate(HelicsApp app, HelicsError* err) +{ + getApp(app, err); + return nullptr; +} + +void helicsAppLoadFile(HelicsApp app, const char* /*configFile*/, HelicsError* err) +{ + getApp(app, err); +} + +void helicsAppInitialize(HelicsApp app, HelicsError* err) +{ + getApp(app, err); +} + +void helicsAppRun(HelicsApp app, HelicsError* err) +{ + getApp(app, err); +} + +void helicsAppRunTo(HelicsApp app, HelicsTime stopTime, HelicsError* err) +{ + getApp(app, err); +} + +void helicsAppFinalize(HelicsApp app, HelicsError* err) +{ + getApp(app, err); +} + +HelicsBool helicsAppIsActive(HelicsApp app) +{ + return HELICS_FALSE; +} diff --git a/src/helics/shared_api_library/helicsExport.cpp b/src/helics/shared_api_library/helicsExport.cpp index a1d89e627f..31891798ea 100644 --- a/src/helics/shared_api_library/helicsExport.cpp +++ b/src/helics/shared_api_library/helicsExport.cpp @@ -10,18 +10,19 @@ SPDX-License-Identifier: BSD-3-Clause #include "../core/coreTypeOperations.hpp" #include "../core/helicsVersion.hpp" #include "../helics.hpp" +#include "../helics_enums.h" +#include "api-data.h" #include "helics/helics-config.h" +#include "helicsApps.h" #include "helicsCore.h" #include "internal/api_objects.h" #include -#include #include -#include #include #include -#include #include +#include #include #include #include @@ -73,35 +74,37 @@ void helicsErrorClear(HelicsError* err) } } -static void signalHandler(int /*signum*/) +namespace { +void signalHandler(int /*signum*/) { helicsAbort(HELICS_ERROR_USER_ABORT, "user abort"); // add a sleep to give the abort a chance to propagate to other federates std::this_thread::sleep_for(std::chrono::milliseconds(50)); - std::cout << std::endl; + std::cout << std::flush; exit(HELICS_ERROR_USER_ABORT); } -static void signalHandlerNoExit(int /*signum*/) +void signalHandlerNoExit(int /*signum*/) { helicsAbort(HELICS_ERROR_USER_ABORT, "user abort"); // add a sleep to give the abort a chance to propagate to other federates std::this_thread::sleep_for(std::chrono::milliseconds(50)); - std::cout << std::endl; + std::cout << std::flush; } -static void signalHandlerThreaded(int signum) +void signalHandlerThreaded(int signum) { std::thread sigthread(signalHandler, signum); sigthread.detach(); } -static void signalHandlerThreadedNoExit(int signum) +void signalHandlerThreadedNoExit(int signum) { std::thread sigthread(signalHandlerNoExit, signum); sigthread.detach(); } +} // namespace void helicsLoadSignalHandler() { static_cast(signal(SIGINT, signalHandler)); @@ -117,9 +120,10 @@ void helicsClearSignalHandler() static_cast(signal(SIGINT, SIG_DFL)); } -static HelicsBool (*keyHandler)(int) = nullptr; +namespace { +HelicsBool (*keyHandler)(int) = nullptr; -static void signalHandlerCallback(int signum) +void signalHandlerCallback(int signum) { HelicsBool runDefaultSignalHandler{HELICS_TRUE}; if (keyHandler != nullptr) { @@ -130,7 +134,7 @@ static void signalHandlerCallback(int signum) } } -static void signalHandlerCallbackNoExit(int signum) +void signalHandlerCallbackNoExit(int signum) { HelicsBool runDefaultSignalHandler{HELICS_TRUE}; if (keyHandler != nullptr) { @@ -141,7 +145,7 @@ static void signalHandlerCallbackNoExit(int signum) } } -static void signalHandlerThreadedCallback(int signum) +void signalHandlerThreadedCallback(int signum) { HelicsBool runDefaultSignalHandler{HELICS_TRUE}; if (keyHandler != nullptr) { @@ -152,7 +156,7 @@ static void signalHandlerThreadedCallback(int signum) } } -static void signalHandlerThreadedCallbackNoExit(int signum) +void signalHandlerThreadedCallbackNoExit(int signum) { HelicsBool runDefaultSignalHandler{HELICS_TRUE}; if (keyHandler != nullptr) { @@ -162,6 +166,7 @@ static void signalHandlerThreadedCallbackNoExit(int signum) signalHandlerThreadedNoExit(signum); } } +} // namespace void helicsLoadSignalHandlerCallback(HelicsBool (*handler)(int), HelicsBool useSeparateThread) { @@ -1098,11 +1103,12 @@ void helicsAbort(int errorCode, const char* message) } } -static constexpr const char* invalidQueryString = "Query object is invalid"; +namespace { +constexpr const char* invalidQueryString = "Query object is invalid"; -static constexpr int validQueryIdentifier = 0x2706'3885; +constexpr int validQueryIdentifier = 0x2706'3885; -static helics::QueryObject* getQueryObj(HelicsQuery query, HelicsError* err) +helics::QueryObject* getQueryObj(HelicsQuery query, HelicsError* err) { if ((err != nullptr) && (err->error_code != 0)) { return nullptr; @@ -1118,7 +1124,7 @@ static helics::QueryObject* getQueryObj(HelicsQuery query, HelicsError* err) } return queryPtr; } - +} // namespace HelicsQuery helicsCreateQuery(const char* target, const char* query) { auto* queryObj = new helics::QueryObject; @@ -1363,6 +1369,15 @@ int MasterObjectHolder::addFed(std::unique_ptr fed) return index; } +int MasterObjectHolder::addApp(std::unique_ptr app) +{ + auto handle = apps.lock(); + auto index = static_cast(handle->size()); + app->index = index; + handle->push_back(std::move(app)); + return index; +} + helics::FedObject* MasterObjectHolder::findFed(std::string_view fedName) { auto handle = feds.lock(); @@ -1449,6 +1464,20 @@ void MasterObjectHolder::clearFed(int index) } } +void MasterObjectHolder::clearApp(int index) +{ + auto appList = apps.lock(); + if ((index < static_cast(appList->size())) && (index >= 0)) { + (*appList)[index]->valid = 0; + (*appList)[index] = nullptr; + if (appList->size() > 10) { + if (std::none_of(appList->begin(), appList->end(), [](const auto& app) { return static_cast(app); })) { + appList->clear(); + } + } + } +} + void MasterObjectHolder::abortAll(int code, std::string_view error) { { @@ -1479,6 +1508,16 @@ void MasterObjectHolder::deleteAll() } fedHandle->clear(); } + { + auto appHandle = apps.lock(); + for (auto& app : appHandle) { + if ((app) && (app->app)) { + helicsAppFinalize(reinterpret_cast(app.get()), nullptr); + app->valid = 0; + } + } + appHandle->clear(); + } { auto coreHandle = cores.lock(); for (auto& core : coreHandle) { diff --git a/src/helics/shared_api_library/internal/api_objects.h b/src/helics/shared_api_library/internal/api_objects.h index 6db3f6372e..a76ec6ac02 100644 --- a/src/helics/shared_api_library/internal/api_objects.h +++ b/src/helics/shared_api_library/internal/api_objects.h @@ -32,12 +32,17 @@ class Broker; class ValueFederate; class MessageFederate; class CallbackFederate; +class FederateInfo; class Input; class Publication; class Endpoint; class Filter; class Translator; +namespace apps { + class App; +} + class FilterObject; class TranslatorObject; class SmallBuffer; @@ -70,6 +75,15 @@ class CoreObject { /** get the CoreObject from a HelicsCore and verify it is valid*/ CoreObject* getCoreObject(HelicsCore core, HelicsError* err) noexcept; +/** object representing an app*/ +class AppObject { + public: + std::string type; //!< the target of the query + std::shared_ptr app; + int index{-2}; + int valid{0}; +}; + class InputObject; class PublicationObject; class EndpointObject; @@ -204,9 +218,13 @@ helics::Federate* getFed(HelicsFederate fed, HelicsError* err); helics::ValueFederate* getValueFed(HelicsFederate fed, HelicsError* err); helics::MessageFederate* getMessageFed(HelicsFederate fed, HelicsError* err); helics::CallbackFederate* getCallbackFed(HelicsFederate fed, HelicsError* err); +helics::FederateInfo* getFedInfo(HelicsFederateInfo fedInfo, HelicsError* err); helics::Core* getCore(HelicsCore core, HelicsError* err); helics::Broker* getBroker(HelicsBroker broker, HelicsError* err); helics::Message* getMessageObj(HelicsMessage message, HelicsError* err); +helics::apps::App* getApp(HelicsApp, HelicsError* err); +/** generate a new helicsFederate and store it in the master*/ +HelicsFederate generateNewHelicsFederateObject(std::shared_ptr fed, helics::FederateType type); std::unique_ptr getMessageUniquePtr(HelicsMessage message, HelicsError* err); /** create a message object from a message pointer*/ @@ -222,6 +240,8 @@ std::shared_ptr getValueFedSharedPtr(HelicsFederate fed, std::shared_ptr getMessageFedSharedPtr(HelicsFederate fed, HelicsError* err); std::shared_ptr getCallbackFedSharedPtr(HelicsFederate fed, HelicsError* err); std::shared_ptr getCoreSharedPtr(HelicsCore core, HelicsError* err); + +std::shared_ptr getAppSharedPtr(HelicsApp app, HelicsError* err); /**centralized error handler for the C interface*/ void helicsErrorHandler(HelicsError* err) noexcept; /** check if the output argument string is valid @@ -238,6 +258,7 @@ class MasterObjectHolder { guarded>> brokers; guarded>> cores; guarded>> feds; + guarded>> apps; gmlc::concurrency::TripWireDetector tripDetect; //!< detector for library termination guarded> errorStrings; //!< container for strings generated from error conditions public: @@ -254,9 +275,13 @@ class MasterObjectHolder { int addFed(std::unique_ptr fed); /** remove a federate object*/ bool removeFed(std::string_view name, int validationCode); + /** add an app to the holder*/ + int addApp(std::unique_ptr app); + void clearBroker(int index); void clearCore(int index); void clearFed(int index); + void clearApp(int index); void deleteAll(); void abortAll(int errorCode, std::string_view error); /** store an error string to a string buffer diff --git a/tests/helics/shared_library/CMakeLists.txt b/tests/helics/shared_library/CMakeLists.txt index 4ee53763cf..fb12edd5ff 100644 --- a/tests/helics/shared_library/CMakeLists.txt +++ b/tests/helics/shared_library/CMakeLists.txt @@ -30,6 +30,10 @@ set(c_shared_library_test_sources CallbackFederateTests.cpp ) +if(TARGET HELICS::apps) + list(APPEND c_shared_library_test_sources appTests.cpp) +endif() + set(cpp_shared_library_test_sources cpptestFixtures.cpp cppshared-library-tests.cpp @@ -68,6 +72,13 @@ target_compile_definitions( shared-library-tests PRIVATE "-DTEST_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../test_files/\"" ) +if(TARGET HELICS::apps) + target_compile_definitions( + shared-library-tests + PRIVATE "-DAPP_TEST_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../apps/test_files/\"" + ) +endif() + add_test(NAME shared-library-tests COMMAND shared-library-tests) target_compile_definitions( diff --git a/tests/helics/shared_library/TranslatorTests.cpp b/tests/helics/shared_library/TranslatorTests.cpp index 6c1286e129..744837ac45 100644 --- a/tests/helics/shared_library/TranslatorTests.cpp +++ b/tests/helics/shared_library/TranslatorTests.cpp @@ -380,7 +380,7 @@ TEST_F(translator, custom_translator) CE(HelicsFederateState state = helicsFederateGetState(vFed, &err)); EXPECT_TRUE(state == HELICS_STATE_EXECUTION); std::string data = "45.7"; - CE(helicsEndpointSendBytes(e1, data.c_str(), static_cast(data.size()), &err)); + CE(helicsEndpointSendString(e1, data.c_str(), &err)); helicsPublicationPublishDouble(p1, 99.23, &err); diff --git a/tests/helics/shared_library/appTests.cpp b/tests/helics/shared_library/appTests.cpp new file mode 100644 index 0000000000..489e679b93 --- /dev/null +++ b/tests/helics/shared_library/appTests.cpp @@ -0,0 +1,236 @@ +/* +Copyright (c) 2017-2024, +Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable +Energy, LLC. See the top-level NOTICE for additional details. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include +/** these test cases test out the value converters + */ +#include "ctestFixtures.hpp" +#include "helics/helics.h" + +#include +#include +#include +#include +#include + +// select an incorrect app +TEST(app_tests, load_error) +{ + auto err = helicsErrorInitialize(); + + helicsCreateApp("testApp", "whatever", NULL, NULL, &err); + EXPECT_NE(err.error_code, 0); +} + +/** this the same test as in the player tests +just meant to test the methods in C not the player itself +*/ +TEST(app_tests, simple_player) +{ + auto err = helicsErrorInitialize(); + HelicsFederateInfo fedInfo = helicsCreateFederateInfo(); + helicsFederateInfoSetCoreType(fedInfo, HELICS_CORE_TYPE_TEST, &err); + helicsFederateInfoSetCoreName(fedInfo, "pscore1", &err); + helicsFederateInfoSetCoreInitString(fedInfo, "-f2 --autobroker", &err); + + auto play1 = helicsCreateApp("playerc1", "player", NULL, fedInfo, &err); + EXPECT_TRUE(helicsAppIsActive(play1) == HELICS_TRUE); + + auto play1Fed = helicsAppGetFederate(play1, &err); + EXPECT_TRUE(helicsFederateIsValid(play1Fed)); + + helicsAppLoadFile(play1, (std::string(APP_TEST_DIR) + "example1.player").c_str(), &err); + EXPECT_EQ(err.error_code, 0); + auto vFed = helicsCreateValueFederate("block1", fedInfo, &err); + + auto sub1 = helicsFederateRegisterSubscription(vFed, "pub1", nullptr, &err); + auto sub2 = helicsFederateRegisterSubscription(vFed, "pub2", nullptr, &err); + auto err2 = helicsErrorInitialize(); + + auto fut = std::async(std::launch::async, [&play1, &err2]() { helicsAppRun(play1, &err2); }); + helicsFederateEnterExecutingMode(vFed, &err); + auto val = helicsInputGetDouble(sub1, &err); + EXPECT_EQ(val, 0.3); + + auto retTime = helicsFederateRequestTime(vFed, 5, &err); + EXPECT_EQ(retTime, 1.0); + val = helicsInputGetDouble(sub1, &err); + EXPECT_EQ(val, 0.5); + val = helicsInputGetDouble(sub2, &err); + EXPECT_DOUBLE_EQ(val, 0.4); + + retTime = helicsFederateRequestTime(vFed, 5, &err); + EXPECT_EQ(retTime, 2.0); + val = helicsInputGetDouble(sub1, &err); + EXPECT_EQ(val, 0.7); + val = helicsInputGetDouble(sub2, &err); + EXPECT_EQ(val, 0.6); + + retTime = helicsFederateRequestTime(vFed, 5, &err); + EXPECT_EQ(retTime, 3.0); + val = helicsInputGetDouble(sub1, &err); + EXPECT_EQ(val, 0.8); + val = helicsInputGetDouble(sub2, &err); + EXPECT_EQ(val, 0.9); + + retTime = helicsFederateRequestTime(vFed, 5, &err); + EXPECT_EQ(retTime, 5.0); + helicsFederateDestroy(vFed); + fut.get(); + EXPECT_EQ(err2.error_code, 0); + EXPECT_EQ(err.error_code, 0); +} + +TEST(app_tests, recorder) +{ + auto err = helicsErrorInitialize(); + HelicsFederateInfo fedInfo = helicsCreateFederateInfo(); + helicsFederateInfoSetCoreType(fedInfo, HELICS_CORE_TYPE_TEST, &err); + helicsFederateInfoSetCoreName(fedInfo, "rcore1", &err); + helicsFederateInfoSetCoreInitString(fedInfo, "-f2 --autobroker", &err); + + auto rec1 = helicsCreateApp("recc1", "recorder", NULL, fedInfo, &err); + EXPECT_TRUE(helicsAppIsActive(rec1) == HELICS_TRUE); + + helicsAppLoadFile(rec1, (std::string(APP_TEST_DIR) + "example3rec.json").c_str(), &err); + EXPECT_EQ(err.error_code, 0); + + auto vFed = helicsCreateValueFederate("block1", fedInfo, &err); + auto pub1 = + helicsFederateRegisterGlobalPublication(vFed, "pub1", HELICS_DATA_TYPE_DOUBLE, NULL, &err); + auto pub2 = + helicsFederateRegisterGlobalPublication(vFed, "pub2", HELICS_DATA_TYPE_DOUBLE, NULL, &err); + + auto err2 = helicsErrorInitialize(); + + auto fut = + std::async(std::launch::async, [&rec1, &err2]() { helicsAppRunTo(rec1, 4.0, &err2); }); + helicsFederateEnterExecutingMode(vFed, &err); + auto retTime = helicsFederateRequestTime(vFed, 1, &err); + EXPECT_EQ(retTime, 1.0); + helicsPublicationPublishDouble(pub1, 3.4, &err); + + retTime = helicsFederateRequestTime(vFed, 1.5, &err); + EXPECT_EQ(retTime, 1.5); + helicsPublicationPublishDouble(pub2, 5.7, &err); + + retTime = helicsFederateRequestTime(vFed, 2, &err); + EXPECT_EQ(retTime, 2.0); + helicsPublicationPublishDouble(pub1, 4.7, &err); + + retTime = helicsFederateRequestTime(vFed, 3.0, &err); + EXPECT_EQ(retTime, 3.0); + helicsPublicationPublishString(pub2, "3.9", &err); + + retTime = helicsFederateRequestTime(vFed, 5.0, &err); + EXPECT_EQ(retTime, 5.0); + + helicsFederateDestroy(vFed); + + fut.get(); + + helicsAppDestroy(rec1); + + EXPECT_EQ(helicsAppIsActive(rec1), HELICS_FALSE); +} + +TEST(app_tests, connector) +{ + auto err = helicsErrorInitialize(); + HelicsFederateInfo fedInfo = helicsCreateFederateInfo(); + helicsFederateInfoSetCoreType(fedInfo, HELICS_CORE_TYPE_TEST, &err); + helicsFederateInfoSetTimeProperty(fedInfo, HELICS_PROPERTY_TIME_PERIOD, 1.0, &err); + helicsFederateInfoSetCoreName(fedInfo, "ccoref5", &err); + helicsFederateInfoSetCoreInitString(fedInfo, "-f2 --autobroker", &err); + + auto conn1 = helicsCreateApp("connectorc1", "connector", NULL, fedInfo, &err); + EXPECT_TRUE(helicsAppIsActive(conn1) == HELICS_TRUE); + + helicsAppLoadFile(conn1, + (std::string(APP_TEST_DIR) + "connector/simple_tags.txt").c_str(), + &err); + EXPECT_EQ(err.error_code, 0); + + auto vFed = helicsCreateValueFederate("c1", fedInfo, &err); + + auto pub1 = helicsFederateRegisterGlobalPublication( + vFed, "pub1", HELICS_DATA_TYPE_DOUBLE, nullptr, &err); + + auto inp1 = + helicsFederateRegisterGlobalInput(vFed, "inp1", HELICS_DATA_TYPE_DOUBLE, nullptr, &err); + auto inp2 = + helicsFederateRegisterGlobalInput(vFed, "inp2", HELICS_DATA_TYPE_DOUBLE, nullptr, &err); + helicsFederateSetGlobal(vFed, "tag2", "true", &err); + auto err2 = helicsErrorInitialize(); + auto fut = std::async(std::launch::async, [&conn1, &err2]() { helicsAppRun(conn1, &err2); }); + helicsFederateEnterExecutingMode(vFed, &err); + + const double testValue = 3452.562; + helicsPublicationPublishDouble(pub1, testValue, &err); + + auto retTime = helicsFederateRequestTime(vFed, 5.0, &err); + EXPECT_EQ(retTime, 1.0); + auto val = helicsInputGetDouble(inp1, &err); + EXPECT_EQ(val, HELICS_INVALID_DOUBLE); + + val = helicsInputGetDouble(inp2, &err); + EXPECT_EQ(val, testValue); + helicsFederateDestroy(vFed); + fut.get(); + EXPECT_EQ(err2.error_code, 0); + + helicsAppDestroy(conn1); +} + +TEST(app_tests, echo) +{ + auto err = helicsErrorInitialize(); + HelicsFederateInfo fedInfo = helicsCreateFederateInfo(); + helicsFederateInfoSetCoreType(fedInfo, HELICS_CORE_TYPE_TEST, &err); + helicsFederateInfoSetCoreName(fedInfo, "ecore4-file", &err); + helicsFederateInfoSetCoreInitString(fedInfo, "-f2 --autobroker", &err); + + auto echo1 = helicsCreateApp("echoc1", "echo", NULL, fedInfo, &err); + EXPECT_TRUE(helicsAppIsActive(echo1) == HELICS_TRUE); + + helicsAppLoadFile(echo1, (std::string(APP_TEST_DIR) + "echo_example.json").c_str(), &err); + EXPECT_EQ(err.error_code, 0); + + auto mFed = helicsCreateMessageFederate("source", fedInfo, &err); + + auto ep1 = helicsFederateRegisterEndpoint(mFed, "src", "", &err); + auto err2 = helicsErrorInitialize(); + auto fut = + std::async(std::launch::async, [&echo1, &err2]() { helicsAppRunTo(echo1, 5.0, &err2); }); + helicsFederateEnterExecutingMode(mFed, &err); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + helicsEndpointSendStringTo(ep1, "hello world", "test", &err); + helicsFederateRequestTime(mFed, 1.0, &err); + helicsEndpointSendStringTo(ep1, "hello again", "test2", &err); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + EXPECT_FALSE(helicsEndpointHasMessage(ep1)); + auto ntime = helicsFederateRequestTime(mFed, 2.0, &err); + EXPECT_DOUBLE_EQ(ntime, HELICS_TIME_EPSILON + 1.2); + EXPECT_TRUE(helicsEndpointHasMessage(ep1)); + auto message = helicsEndpointGetMessage(ep1); + ASSERT_TRUE(message); + EXPECT_STREQ(helicsMessageGetString(message), "hello world"); + EXPECT_STREQ(helicsMessageGetSource(message), "test"); + + ntime = helicsFederateRequestTime(mFed, 3.0, &err); + EXPECT_EQ(ntime, 2.2); + EXPECT_TRUE(helicsEndpointHasMessage(ep1)); + helicsMessageFree(message); + message = helicsEndpointGetMessage(ep1); + ASSERT_TRUE(message); + EXPECT_STREQ(helicsMessageGetString(message), "hello again"); + EXPECT_STREQ(helicsMessageGetSource(message), "test2"); + helicsMessageFree(message); + helicsFederateDestroy(mFed); + fut.get(); + EXPECT_EQ(err2.error_code, 0); +} diff --git a/tests/helics/shared_library/badInputTests.cpp b/tests/helics/shared_library/badInputTests.cpp index 62825b9bb1..78bc17cd28 100644 --- a/tests/helics/shared_library/badInputTests.cpp +++ b/tests/helics/shared_library/badInputTests.cpp @@ -932,6 +932,37 @@ TEST_F(function_nosan, messageFed_event) EXPECT_NE(err.error_code, 0); } +TEST_F(function_nosan, messageFed_string_event) +{ + SetupTest(helicsCreateMessageFederate, "test", 1); + auto mFed1 = GetFederateAt(0); + + auto ept1 = helicsFederateRegisterGlobalEndpoint(mFed1, "ept1", "", nullptr); + EXPECT_NE(ept1, nullptr); + auto ept2 = helicsFederateRegisterGlobalEndpoint(mFed1, "ept1", "", &err); + EXPECT_NE(err.error_code, 0); + EXPECT_EQ(ept2, nullptr); + helicsErrorClear(&err); + // send events without destinations + helicsEndpointSetDefaultDestination(ept1, "ept1", nullptr); + helicsFederateEnterExecutingMode(mFed1, nullptr); + + helicsEndpointSendStringAt(ept1, nullptr, 0.0, &err); + + helicsEndpointSendStringToAt(ept1, "ept1", nullptr, 0.0, &err); + + char data[5] = "test"; + helicsEndpointSendStringAt(ept1, data, 0.0, &err); + helicsFederateRequestNextStep(mFed1, nullptr); + auto cnt = helicsEndpointPendingMessageCount(ept1); + EXPECT_EQ(cnt, 3); + + helicsFederateFinalize(mFed1, nullptr); + // can't send an event after the federate is finalized + helicsEndpointSendStringAt(ept1, data, 0.0, &err); + EXPECT_NE(err.error_code, 0); +} + TEST_F(function_nosan, messageFed_messageObject) { SetupTest(helicsCreateMessageFederate, "test", 1); diff --git a/tests/helics/shared_library/evilInputTests.cpp b/tests/helics/shared_library/evilInputTests.cpp index 9205bda003..f4a029fb16 100644 --- a/tests/helics/shared_library/evilInputTests.cpp +++ b/tests/helics/shared_library/evilInputTests.cpp @@ -15,21 +15,21 @@ SPDX-License-Identifier: BSD-3-Clause TEST(evil_general_test, helicsErrorInitialize) { // HelicsError helicsErrorInitialize(void); - auto E = helicsErrorInitialize(); - EXPECT_EQ(E.error_code, 0); - EXPECT_TRUE(std::string(E.message).empty()); + auto err = helicsErrorInitialize(); + EXPECT_EQ(err.error_code, 0); + EXPECT_TRUE(std::string(err.message).empty()); } TEST(evil_general_test, helicsErrorClear) { // void helicsErrorClear(HelicsError* err); - auto E = helicsErrorInitialize(); - E.error_code = 55; - E.message = "this is a test"; + auto err = helicsErrorInitialize(); + err.error_code = 55; + err.message = "this is a test"; - helicsErrorClear(&E); - EXPECT_EQ(E.error_code, 0); - EXPECT_TRUE(std::string(E.message).empty()); + helicsErrorClear(&err); + EXPECT_EQ(err.error_code, 0); + EXPECT_TRUE(std::string(err.message).empty()); } TEST(evil_general_test, helicsIsCoreTypeAvailable) @@ -289,8 +289,8 @@ TEST(evil_creation_test, helicsCreateFederateInfo) TEST(evil_creation_test, helicsCreateQuery) { // HelicsQuery helicsCreateQuery(const char* target, const char* query); - auto q = helicsCreateQuery(nullptr, nullptr); - EXPECT_NE(q, nullptr); + auto query = helicsCreateQuery(nullptr, nullptr); + EXPECT_NE(query, nullptr); } // section Core Functions @@ -2645,12 +2645,12 @@ TEST(evil_input_test, helicsInputGetDouble) err.error_code = 45; auto res1 = helicsInputGetDouble(nullptr, &err); EXPECT_EQ(err.error_code, 45); - EXPECT_EQ(res1, HELICS_TIME_INVALID); + EXPECT_EQ(res1, HELICS_INVALID_DOUBLE); helicsErrorClear(&err); auto res2 = helicsInputGetDouble(nullptr, nullptr); - EXPECT_EQ(res2, HELICS_TIME_INVALID); + EXPECT_EQ(res2, HELICS_INVALID_DOUBLE); auto res3 = helicsInputGetDouble(evil_input, &err); - EXPECT_EQ(res3, HELICS_TIME_INVALID); + EXPECT_EQ(res3, HELICS_INVALID_DOUBLE); EXPECT_NE(err.error_code, 0); } @@ -2681,13 +2681,13 @@ TEST(evil_input_test, helicsInputGetChar) err.error_code = 45; char res1 = helicsInputGetChar(nullptr, &err); EXPECT_EQ(err.error_code, 45); - char tc = '\x15'; - EXPECT_TRUE(res1 == tc); + char testChar = '\x15'; + EXPECT_TRUE(res1 == testChar); helicsErrorClear(&err); char res2 = helicsInputGetChar(nullptr, nullptr); - EXPECT_TRUE(res2 == tc); + EXPECT_TRUE(res2 == testChar); char res3 = helicsInputGetChar(evil_input, &err); - EXPECT_TRUE(res3 == tc); + EXPECT_TRUE(res3 == testChar); EXPECT_NE(err.error_code, 0); } @@ -2719,12 +2719,12 @@ TEST(evil_input_test, helicsInputGetComplex) helicsInputGetComplex(nullptr, nullptr, nullptr, &err); EXPECT_EQ(err.error_code, 45); helicsErrorClear(&err); - double v1 = 19.4; - double v2 = 18.3; + double value1 = 19.4; + double value2 = 18.3; // auto res2=helicsInputGetComplex(HelicsInput ipt, double* real, double* imag, nullptr); - helicsInputGetComplex(evil_input, &v1, &v2, &err); - EXPECT_DOUBLE_EQ(v1, 19.4); - EXPECT_DOUBLE_EQ(v2, 18.3); + helicsInputGetComplex(evil_input, &value1, &value2, &err); + EXPECT_DOUBLE_EQ(value1, 19.4); + EXPECT_DOUBLE_EQ(value2, 18.3); EXPECT_NE(err.error_code, 0); } @@ -3709,6 +3709,56 @@ TEST(evil_endpoint_test, helicsEndpointSendBytesAt) EXPECT_NE(err.error_code, 0); } +// send string + +TEST(evil_endpoint_test, helicsEndpointSendStringTo) +{ + // void helicsEndpointSendMessage(HelicsEndpoint endpoint, const char* dest, const void* + // data, int inputDataLength, HelicsError* err); + char rdata[256]; + auto evil_ept = reinterpret_cast(rdata); + auto err = helicsErrorInitialize(); + err.error_code = 45; + helicsEndpointSendStringTo(nullptr, nullptr, nullptr, &err); + EXPECT_EQ(err.error_code, 45); + helicsErrorClear(&err); + // auto res2=helicsEndpointSendMessage(nullptr, nullptr, nullptr, int inputDataLength, + // nullptr); + helicsEndpointSendStringTo(evil_ept, rdata, "dest", &err); + EXPECT_NE(err.error_code, 0); +} + +TEST(evil_endpoint_test, helicsEndpointSendStringToAt) +{ + // void helicsEndpointStringToAt(HelicsEndpoint endpoint, const char* dest, const void* + // data, int inputDataLength, HelicsError* err); + char rdata[256]; + auto evil_ept = reinterpret_cast(rdata); + auto err = helicsErrorInitialize(); + err.error_code = 45; + helicsEndpointSendStringToAt(nullptr, nullptr, nullptr, 0.0, &err); + EXPECT_EQ(err.error_code, 45); + helicsErrorClear(&err); + helicsEndpointSendStringToAt(evil_ept, rdata, "dest", -15.7, &err); + EXPECT_NE(err.error_code, 0); +} + +TEST(evil_endpoint_test, helicsEndpointSendStringAt) +{ + // void helicsEndpointSendStringAt( HelicsEndpoint endpoint, const char* dest, const + // void* data, int inputDataLength, HelicsTime time, HelicsError* err); + char rdata[256]; + auto evil_ept = reinterpret_cast(rdata); + auto err = helicsErrorInitialize(); + err.error_code = 45; + helicsEndpointSendStringAt(nullptr, nullptr, 3.5, &err); + EXPECT_EQ(err.error_code, 45); + helicsErrorClear(&err); + helicsEndpointSendStringAt(evil_ept, rdata, 3.5, &err); + EXPECT_NE(err.error_code, 0); +} +// + TEST(evil_endpoint_test, helicsEndpointSendMessageObject) { // void helicsEndpointSendMessageObject(HelicsEndpoint endpoint, HelicsMessage message, diff --git a/tests/helics/shared_library/test-message-federate.cpp b/tests/helics/shared_library/test-message-federate.cpp index 557e3ffd10..c63670aae4 100644 --- a/tests/helics/shared_library/test-message-federate.cpp +++ b/tests/helics/shared_library/test-message-federate.cpp @@ -122,6 +122,49 @@ TEST_P(mfed_simple_type_tests, send_receive) EXPECT_TRUE(mFed1State == HelicsFederateState::HELICS_STATE_FINALIZE); } +TEST_F(mfed_tests, send_receive_string) +{ + SetupTest(helicsCreateMessageFederate, "test", 1); + auto mFed1 = GetFederateAt(0); + + auto epid = helicsFederateRegisterEndpoint(mFed1, "ep1", nullptr, &err); + auto epid2 = helicsFederateRegisterGlobalEndpoint(mFed1, "ep2", "random", &err); + EXPECT_EQ(err.error_code, HELICS_OK); + CE(helicsFederateSetTimeProperty(mFed1, HELICS_PROPERTY_TIME_DELTA, 1.0, &err)); + + CE(helicsFederateEnterExecutingMode(mFed1, &err)); + + CE(HelicsFederateState mFed1State = helicsFederateGetState(mFed1, &err)); + EXPECT_TRUE(mFed1State == HELICS_STATE_EXECUTION); + std::string data(500, 'a'); + + CE(helicsEndpointSendStringToAt(epid, data.c_str(), "ep2", 0.0, &err)); + HelicsTime time; + CE(time = helicsFederateRequestTime(mFed1, 1.0, &err)); + EXPECT_EQ(time, 1.0); + + auto res = helicsFederateHasMessage(mFed1); + EXPECT_TRUE(res); + res = helicsEndpointHasMessage(epid); + EXPECT_TRUE(res == false); + res = helicsEndpointHasMessage(epid2); + EXPECT_TRUE(res); + + auto M = helicsEndpointGetMessage(epid2); + // ASSERT_TRUE (M); + ASSERT_EQ(helicsMessageGetByteCount(M), 500); + char* dptr = reinterpret_cast(helicsMessageGetBytesPointer(M)); + if (dptr != nullptr) { + EXPECT_EQ(dptr[245], 'a'); + } else { + ASSERT_TRUE(false) << "data is nullptr"; + } + CE(helicsFederateFinalize(mFed1, &err)); + + CE(mFed1State = helicsFederateGetState(mFed1, &err)); + EXPECT_TRUE(mFed1State == HelicsFederateState::HELICS_STATE_FINALIZE); +} + TEST_P(mfed_simple_type_tests, send_receive_mobj) { SetupTest(helicsCreateMessageFederate, GetParam(), 1);