diff --git a/src/helics/apps/Connector.cpp b/src/helics/apps/Connector.cpp index f7f3ce0153..3a9f3fc379 100644 --- a/src/helics/apps/Connector.cpp +++ b/src/helics/apps/Connector.cpp @@ -290,10 +290,11 @@ Connector::Connector(std::string_view appName, const std::string& configString): Connector::loadJsonFile(configString); } -std::string_view Connector::addTag(std::string_view tagName) +std::size_t Connector::addTag(std::string_view tagName) { - auto tagIterator = tags.insert(std::string(tagName)); - return {*(tagIterator.first)}; + std::size_t hash=std::hash()(tagName); + tags.emplace(hash,tagName); + return hash; } std::string_view Connector::addInterface(std::string_view interfaceName) @@ -333,7 +334,7 @@ void Connector::addConnection(std::string_view interface1, InterfaceDirection direction, const std::vector& connectionTags) { - std::vector svtags; + std::vector svtags; svtags.reserve(connectionTags.size()); for (const auto& tag : connectionTags) { svtags.push_back(addTag(tag)); @@ -508,7 +509,7 @@ void Connector::loadJsonFile(const std::string& jsonString) } std::vector - Connector::buildPossibleConnectionList(std::string_view startingInterface) const + Connector::buildPossibleConnectionList(std::string_view startingInterface, const std::vector &tags) const { std::vector matches; auto [first, last] = connections.equal_range(startingInterface); @@ -593,11 +594,11 @@ static std::set } bool Connector::makePotentialConnection( - std::string_view interface, + std::string_view interface, const std::vector &tags, std::unordered_map& potentials, const std::unordered_multimap& aliases) { - auto connectionOptions = buildPossibleConnectionList(interface); + auto connectionOptions = buildPossibleConnectionList(interface,tags); for (const auto& option : connectionOptions) { auto located = potentials.find(option.interface2); if (located != potentials.end()) { @@ -619,21 +620,21 @@ bool Connector::makePotentialConnection( } bool Connector::checkPotentialConnection( - std::string_view interfaceName, + std::string_view interfaceName, const std::vector &tags, std::unordered_set& possibleConnections, std::unordered_map& potentials, const std::unordered_multimap& aliases) { static auto nullConnector = [this](std::string_view, std::string_view) {}; /** potential inputs*/ - auto matched = makeTargetConnection(interfaceName, + auto matched = makeTargetConnection(interfaceName,tags, possibleConnections, aliases, nullConnector); if (matched > 0) { return true; } - if (makePotentialConnection(interfaceName,potentials,aliases)) { + if (makePotentialConnection(interfaceName,tags,potentials,aliases)) { return true; } if (!aliases.empty()) { @@ -642,7 +643,7 @@ bool Connector::checkPotentialConnection( if (alias == interfaceName) { continue; } - if (makePotentialConnection(alias,potentials,aliases)) { + if (makePotentialConnection(alias,tags,potentials,aliases)) { return true; } } @@ -651,13 +652,13 @@ bool Connector::checkPotentialConnection( } int Connector::makeTargetConnection( - std::string_view origin, + std::string_view origin, const std::vector &tags, std::unordered_set& possibleConnections, const std::unordered_multimap& aliases, const std::function& callback) { int matched{0}; - auto connectionOptions = buildPossibleConnectionList(origin); + auto connectionOptions = buildPossibleConnectionList(origin,tags); for (const auto& option : connectionOptions) { auto located = possibleConnections.find(option.interface2); if (located != possibleConnections.end()) { @@ -694,7 +695,7 @@ int Connector::makeTargetConnection( if (alias == origin) { continue; } - auto aliasOptions = buildPossibleConnectionList(alias); + auto aliasOptions = buildPossibleConnectionList(alias,tags); for (const auto& option : aliasOptions) { auto located = possibleConnections.find(option.interface2); if (located != possibleConnections.end()) { @@ -744,16 +745,18 @@ void Connector::makeConnections(ConnectionsList& possibleConnections) auto targetEndpointConnector = [this](std::string_view origin, std::string_view source) { core.linkEndpoints(source, origin); }; + + std::vector tagList; /** unconnected inputs*/ for (const auto& uInp : possibleConnections.unconnectedInputs) { - matchCount += makeTargetConnection(uInp, + matchCount += makeTargetConnection(uInp,tagList, possibleConnections.pubs, possibleConnections.aliases, inputConnector); } /** unconnected publications*/ for (const auto& uPub : possibleConnections.unconnectedPubs) { - matchCount += makeTargetConnection(uPub, + matchCount += makeTargetConnection(uPub,tagList, possibleConnections.inputs, possibleConnections.aliases, pubConnector); @@ -761,7 +764,7 @@ void Connector::makeConnections(ConnectionsList& possibleConnections) /** unconnected source endpoints*/ for (const auto& uEnd : possibleConnections.unconnectedSourceEndpoints) { - matchCount += makeTargetConnection(uEnd, + matchCount += makeTargetConnection(uEnd,tagList, possibleConnections.endpoints, possibleConnections.aliases, sourceEndpointConnector); @@ -770,7 +773,7 @@ void Connector::makeConnections(ConnectionsList& possibleConnections) if (matchTargetEndpoints) { /** unconnected target endpoints*/ for (const auto& uEnd : possibleConnections.unconnectedTargetEndpoints) { - matchCount += makeTargetConnection(uEnd, + matchCount += makeTargetConnection(uEnd,tagList, possibleConnections.endpoints, possibleConnections.aliases, targetEndpointConnector); @@ -781,9 +784,10 @@ void Connector::makeConnections(ConnectionsList& possibleConnections) void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnections) { auto nullConnector = [this](std::string_view, std::string_view) {}; + std::vector tagList; /** potential inputs*/ for (auto& pInp : possibleConnections.potentialInputs) { - if (checkPotentialConnection(pInp.first, possibleConnections.pubs, possibleConnections.potentialPubs, possibleConnections.aliases)) + if (checkPotentialConnection(pInp.first,tagList, possibleConnections.pubs, possibleConnections.potentialPubs, possibleConnections.aliases)) { pInp.second.used=true; } @@ -793,7 +797,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection if (pPub.second.used) { continue; } - if (checkPotentialConnection(pPub.first, possibleConnections.inputs, possibleConnections.potentialInputs, possibleConnections.aliases)) + if (checkPotentialConnection(pPub.first,tagList, possibleConnections.inputs, possibleConnections.potentialInputs, possibleConnections.aliases)) { pPub.second.used=true; } @@ -804,7 +808,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection if (pEnd.second.used) { continue; } - if (checkPotentialConnection(pEnd.first, possibleConnections.endpoints, possibleConnections.potentialEndpoints, possibleConnections.aliases)) + if (checkPotentialConnection(pEnd.first,tagList, possibleConnections.endpoints, possibleConnections.potentialEndpoints, possibleConnections.aliases)) { pEnd.second.used=true; } @@ -812,7 +816,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection /** now try to match unconnected interfaces to some of the potential ones*/ /** unconnected inputs*/ for (const auto& uInp : possibleConnections.unconnectedInputs) { - if (makePotentialConnection(uInp, + if (makePotentialConnection(uInp,tagList, possibleConnections.potentialPubs, possibleConnections.aliases)) { continue; @@ -823,7 +827,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection if (alias == uInp) { continue; } - if (makePotentialConnection(alias, + if (makePotentialConnection(alias,tagList, possibleConnections.potentialPubs, possibleConnections.aliases)) { break; @@ -834,7 +838,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection /** unconnected publications*/ for (const auto& uPub : possibleConnections.unconnectedPubs) { - if (makePotentialConnection(uPub, + if (makePotentialConnection(uPub,tagList, possibleConnections.potentialInputs, possibleConnections.aliases)) { continue; @@ -845,7 +849,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection if (alias == uPub) { continue; } - if (makePotentialConnection(alias, + if (makePotentialConnection(alias,tagList, possibleConnections.potentialInputs, possibleConnections.aliases)) { break; @@ -856,7 +860,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection /** unconnected source endpoints*/ for (const auto& uEnd : possibleConnections.unconnectedSourceEndpoints) { - if (makePotentialConnection(uEnd, + if (makePotentialConnection(uEnd,tagList, possibleConnections.potentialEndpoints, possibleConnections.aliases)) { continue; @@ -867,7 +871,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection if (alias == uEnd) { continue; } - if (makePotentialConnection(alias, + if (makePotentialConnection(alias,tagList, possibleConnections.potentialEndpoints, possibleConnections.aliases)) { break; @@ -878,7 +882,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection /** unconnected source endpoints*/ for (const auto& uEnd : possibleConnections.unconnectedTargetEndpoints) { - if (makePotentialConnection(uEnd, + if (makePotentialConnection(uEnd,tagList, possibleConnections.potentialEndpoints, possibleConnections.aliases)) { continue; @@ -889,7 +893,7 @@ void Connector::establishPotentialInterfaces(ConnectionsList& possibleConnection if (alias == uEnd) { continue; } - if (makePotentialConnection(alias, + if (makePotentialConnection(alias,tagList, possibleConnections.potentialEndpoints, possibleConnections.aliases)) { break; diff --git a/src/helics/apps/Connector.hpp b/src/helics/apps/Connector.hpp index 7629baed23..7c3f26f53e 100644 --- a/src/helics/apps/Connector.hpp +++ b/src/helics/apps/Connector.hpp @@ -23,7 +23,7 @@ struct Connection { std::string_view interface1; std::string_view interface2; InterfaceDirection direction; - std::vector tags; + std::vector tags; std::shared_ptr stringBuffer; }; @@ -103,7 +103,7 @@ necessary const std::vector& tags = {}); /** add a tag for later reference return a string_view reference for the tag*/ - std::string_view addTag(std::string_view tagName); + std::size_t addTag(std::string_view tagName); /** add a interface name for later reference return a string_view reference for the interface * name*/ @@ -135,21 +135,24 @@ necessary /** try to make a connection for an input*/ int makeTargetConnection( std::string_view origin, + const std::vector &tags, std::unordered_set& possibleConnections, const std::unordered_multimap& aliases, const std::function& callback); bool makePotentialConnection( std::string_view interfaceName, + const std::vector &tags, std::unordered_map& potentials, const std::unordered_multimap& aliases); bool checkPotentialConnection( std::string_view interface, + const std::vector &tags, std::unordered_set& possibleConnections, std::unordered_map& potentials, const std::unordered_multimap& aliases); /** get a list of the possible connections to based on the database*/ - std::vector buildPossibleConnectionList(std::string_view startingInterface) const; + std::vector buildPossibleConnectionList(std::string_view startingInterface,const std::vector &tags) const; /** load the regex matchers */ void generateRegexMatchers(); @@ -159,7 +162,7 @@ necessary std::unordered_multimap connections; std::vector matchers; std::vector> regexMatchers; - std::unordered_set tags; + std::unordered_map tags; std::unordered_set interfaces; std::uint64_t matchCount{0}; /// indicator to match unconnected target endpoints default{false} diff --git a/tests/helics/apps/CMakeLists.txt b/tests/helics/apps/CMakeLists.txt index 6a3b3c52ac..9896c6f438 100644 --- a/tests/helics/apps/CMakeLists.txt +++ b/tests/helics/apps/CMakeLists.txt @@ -28,6 +28,7 @@ set(helics_apps_test_sources ConnectorTests2.cpp ConnectorFileTests.cpp Connector2StageTests.cpp + ConnectorTagTests.cpp exeTestHelper.h ) diff --git a/tests/helics/apps/ConnectorTagTests.cpp b/tests/helics/apps/ConnectorTagTests.cpp new file mode 100644 index 0000000000..9ca8c8e346 --- /dev/null +++ b/tests/helics/apps/ConnectorTagTests.cpp @@ -0,0 +1,49 @@ +/* +Copyright (c) 2017-2023, +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 "gtest/gtest.h" +#include +#ifndef DISABLE_SYSTEM_CALL_TESTS +# include "exeTestHelper.h" +#endif + +#include "helics/apps/BrokerApp.hpp" +#include "helics/apps/Connector.hpp" +#include "helics/apps/CoreApp.hpp" + +#include +#include + +static constexpr std::string_view testdir = TEST_DIR "/connector/"; + +TEST(connector_tags, no_match_tag) +{ + helics::FederateInfo fedInfo(helics::CoreType::TEST); + using helics::apps::InterfaceDirection; + + fedInfo.coreName = "ccore1"; + fedInfo.coreInitString = "-f2 --autobroker"; + fedInfo.setProperty(HELICS_PROPERTY_TIME_PERIOD, 1.0); + helics::apps::Connector conn1("connector1", fedInfo); + conn1.addConnection("inp1", "pub1", InterfaceDirection::FROM_TO,{"tag1"}); + + helics::ValueFederate vfed("c1", fedInfo); + auto& pub1 = vfed.registerGlobalPublication("pub1"); + auto& inp1 = vfed.registerGlobalInput("inp1"); + + auto fut = std::async(std::launch::async, [&conn1]() { conn1.run(); }); + vfed.enterExecutingMode(); + const double testValue = 3452.562; + pub1.publish(testValue); + auto retTime = vfed.requestTime(5); + EXPECT_EQ(retTime, 1.0); + auto val = inp1.getDouble(); + EXPECT_EQ(val, testValue); + + vfed.finalize(); + fut.get(); + EXPECT_EQ(conn1.madeConnections(), 0); +}