diff --git a/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/fixed_size_container.hpp b/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/fixed_size_container.hpp deleted file mode 100644 index 57e1da73eb5..00000000000 --- a/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/fixed_size_container.hpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2019, 2021 by Robert Bosch GmbH, Apex.AI Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -#ifndef IOX_POSH_ROUDI_INTROSPECTION_FIXED_SIZE_CONTAINER_HPP -#define IOX_POSH_ROUDI_INTROSPECTION_FIXED_SIZE_CONTAINER_HPP - -#include "iox/vector.hpp" - -#include - - -namespace iox -{ -namespace roudi -{ -/// @details allows allocating a predefined capacity of T objects on the stack -/// and using there pointers outside -/// (pointers stay valid until object is removed from theFixedSizeContainer) -/// therefore we avoid heap allocation but we can still use pointers to objects -/// for efficient update/passing until we exhaust the fixed size container - -/// @attention no bounds checking during access for efficiency (as in STL containers) -/// access to indices < 0 or >= capacity is undefined behaviour (most likely a -/// segmentation fault) -template -class FixedSizeContainer -{ - public: - using Index_t = int32_t; - using Capacity_t = decltype(capacity); - static constexpr int32_t NOT_AN_ELEMENT = -1; - - FixedSizeContainer() noexcept - : m_values(capacity) - { - } - - /// @note returns index or -1 if element could not be added - /// a successful add returns an arbitrary index which can be non consecutive - /// for consecutive adds - Index_t add(const T& element) noexcept - { - auto nextElement = nextFree(); - - if (nextElement >= 0) - { - m_freeIndex = nextElement; - m_values[static_cast(m_freeIndex)].value = element; - m_values[static_cast(m_freeIndex)].isValid = true; - ++m_size; - } - - return nextElement; - } - - void remove(Index_t index) noexcept - { - if (m_values[static_cast(index)].isValid) - { - m_values[static_cast(index)].isValid = false; - --m_size; - } - } - - /// @note access can change the underlying object, without modifying valid flag - /// if the index is invalid than the behavior is undefined - T& operator[](Index_t index) noexcept - { - return m_values[static_cast(index)].value; - } - - T* get(Index_t index) noexcept - { - return (m_values[static_cast(index)].isValid) ? &m_values[static_cast(index)].value - : nullptr; - } - - size_t size() noexcept - { - return m_size; - } - - private: - Index_t nextFree() noexcept - { - if (m_size >= capacity) - return NOT_AN_ELEMENT; // container is full - - for (; m_values[static_cast(m_freeIndex)].isValid; - m_freeIndex = (m_freeIndex + 1) % static_cast(capacity)) - ; - - return m_freeIndex; - } - - void setValid(Index_t index, bool value = true) noexcept - { - m_values[static_cast(index)].isValid = value; - } - - void setInvalid(Index_t index) noexcept - { - setValid(index, false); - } - - Index_t m_freeIndex{0}; - size_t m_size{0U}; - - struct entry_t - { - T value = T(); - bool isValid = false; - }; - - iox::vector m_values; -}; - -} // namespace roudi -} // namespace iox - -#endif // IOX_POSH_ROUDI_INTROSPECTION_FIXED_SIZE_CONTAINER_HPP diff --git a/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.hpp b/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.hpp index 68301761ed6..1f6b5a9b9cb 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.hpp @@ -17,11 +17,11 @@ #ifndef IOX_POSH_ROUDI_INTROSPECTION_PORT_INTROSPECTION_HPP #define IOX_POSH_ROUDI_INTROSPECTION_PORT_INTROSPECTION_HPP -#include "fixed_size_container.hpp" #include "iceoryx_hoofs/internal/concurrent/periodic_task.hpp" #include "iceoryx_posh/iceoryx_posh_types.hpp" #include "iceoryx_posh/internal/popo/ports/publisher_port_data.hpp" #include "iceoryx_posh/roudi/introspection_types.hpp" +#include "iox/fixed_position_container.hpp" #include "iox/function.hpp" #include @@ -55,10 +55,16 @@ class PortIntrospection class PortData { private: - /// internal helper classes + struct Dummy + { + }; + using PublisherContainerIndexType = typename FixedPositionContainer::IndexType; + using ConnectionContainerIndexType = typename FixedPositionContainer::IndexType; struct ConnectionInfo; + /// internal helper classes + struct PublisherInfo { PublisherInfo() noexcept @@ -83,8 +89,8 @@ class PortIntrospection TimePointNs_t m_sequenceNumberTimestamp{DurationNs_t(0)}; mepoo::SequenceNumber_t m_sequenceNumber{0U}; - /// map from indices to object pointers - std::map connectionMap; + /// map from indices to ConnectionContainer indices + std::map connectionMap; int index{-1}; }; @@ -123,12 +129,12 @@ class PortIntrospection } SubscriberInfo subscriberInfo; - PublisherInfo* publisherInfo{nullptr}; + iox::optional publisherInfoIndex; ConnectionState state{ConnectionState::DEFAULT}; bool isConnected() const noexcept { - return publisherInfo && state == ConnectionState::CONNECTED; + return publisherInfoIndex.has_value() && state == ConnectionState::CONNECTED; } }; @@ -208,16 +214,14 @@ class PortIntrospection void setNew(bool value) noexcept; private: - using PublisherContainer = FixedSizeContainer; - using ConnectionContainer = FixedSizeContainer; + using PublisherContainer = FixedPositionContainer; + using ConnectionContainer = FixedPositionContainer; /// @brief inner map maps from unique port IDs to indices in the PublisherContainer - std::map> - m_publisherMap; + std::map> m_publisherMap; /// inner map maps from unique port IDs to indices in the ConnectionContainer - std::map> - m_connectionMap; + std::map> m_connectionMap; /// @note we avoid allocating the objects on the heap but can still use a map /// to locate/remove them fast(er) diff --git a/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.inl b/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.inl index 3f0010d0e1c..aaf4227915e 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.inl +++ b/iceoryx_posh/include/iceoryx_posh/internal/roudi/introspection/port_introspection.inl @@ -193,8 +193,8 @@ inline bool PortIntrospection::PortData::updateCo for (auto& pair : innerConnectionMap) { - auto& connection = m_connectionContainer[pair.second]; - connection.state = getNextState(connection.state, messageType); + auto connection = m_connectionContainer.iter_from_index(pair.second); + connection->state = getNextState(connection->state, messageType); } setNew(true); @@ -224,8 +224,8 @@ inline bool PortIntrospection::PortData::updateSu return false; } - auto& connection = m_connectionContainer[iterInnerMap->second]; - connection.state = getNextState(connection.state, messageType); + auto connection = m_connectionContainer.iter_from_index(iterInnerMap->second); + connection->state = getNextState(connection->state, messageType); setNew(true); return true; @@ -240,8 +240,8 @@ inline bool PortIntrospection::PortData::addPubli auto service = port.m_serviceDescription; auto uniqueId = port.m_uniqueId; - auto index = m_publisherContainer.add(PublisherInfo(port)); - if (index < 0) + auto publisherInfo = m_publisherContainer.emplace(PublisherInfo(port)); + if (publisherInfo == m_publisherContainer.end()) { return false; } @@ -250,8 +250,8 @@ inline bool PortIntrospection::PortData::addPubli if (iter == m_publisherMap.end()) { // service is new, create new map - std::map innerPublisherMap; - innerPublisherMap.insert(std::make_pair(uniqueId, index)); + std::map innerPublisherMap; + innerPublisherMap.insert(std::make_pair(uniqueId, publisherInfo.to_index())); m_publisherMap.insert(std::make_pair(service, innerPublisherMap)); } else @@ -261,7 +261,7 @@ inline bool PortIntrospection::PortData::addPubli auto iter = innerPublisherMap.find(uniqueId); if (iter == innerPublisherMap.end()) { - innerPublisherMap.insert(std::make_pair(uniqueId, index)); + innerPublisherMap.insert(std::make_pair(uniqueId, publisherInfo.to_index())); } else { @@ -270,7 +270,6 @@ inline bool PortIntrospection::PortData::addPubli } // connect publisher to all subscribers with the same Id - PublisherInfo* publisher = m_publisherContainer.get(index); // find corresponding subscribers auto connIter = m_connectionMap.find(service); @@ -279,10 +278,10 @@ inline bool PortIntrospection::PortData::addPubli auto& innerConnectionMap = connIter->second; for (auto& pair : innerConnectionMap) { - auto& connection = m_connectionContainer[pair.second]; - if (service == connection.subscriberInfo.service) + auto connection = m_connectionContainer.iter_from_index(pair.second); + if (service == connection->subscriberInfo.service) { - connection.publisherInfo = publisher; + connection->publisherInfoIndex = publisherInfo.to_index(); } } } @@ -300,8 +299,8 @@ inline bool PortIntrospection::PortData::addSubsc auto service = portData.m_serviceDescription; auto uniqueId = portData.m_uniqueId; - auto index = m_connectionContainer.add(ConnectionInfo(portData)); - if (index < 0) + auto connection = m_connectionContainer.emplace(ConnectionInfo(portData)); + if (connection == m_connectionContainer.end()) { return false; } @@ -311,8 +310,8 @@ inline bool PortIntrospection::PortData::addSubsc if (iter == m_connectionMap.end()) { // service is new, create new map - std::map innerConnectionMap; - innerConnectionMap.insert(std::make_pair(uniqueId, index)); + std::map innerConnectionMap; + innerConnectionMap.insert(std::make_pair(uniqueId, connection.to_index())); m_connectionMap.insert(std::make_pair(service, innerConnectionMap)); } else @@ -322,7 +321,7 @@ inline bool PortIntrospection::PortData::addSubsc auto iter = innerConnectionMap.find(uniqueId); if (iter == innerConnectionMap.end()) { - innerConnectionMap.insert(std::make_pair(uniqueId, index)); + innerConnectionMap.insert(std::make_pair(uniqueId, connection.to_index())); } else { @@ -330,16 +329,22 @@ inline bool PortIntrospection::PortData::addSubsc } } - auto& connection = m_connectionContainer[index]; - auto sendIter = m_publisherMap.find(service); if (sendIter != m_publisherMap.end()) { auto& innerPublisherMap = sendIter->second; for (auto& iter : innerPublisherMap) { - auto publisher = m_publisherContainer.get(iter.second); - connection.publisherInfo = publisher; // set corresponding publisher if exists + auto publisherInfo = m_publisherContainer.iter_from_index(iter.second); + // set corresponding publisher info if exists + if (publisherInfo != m_publisherContainer.end()) + { + connection->publisherInfoIndex = publisherInfo.to_index(); + } + else + { + connection->publisherInfoIndex.reset(); + } } } @@ -365,17 +370,21 @@ PortIntrospection::PortData::removePublisher(cons return false; } auto m_publisherIndex = iterInnerMap->second; - auto& publisher = m_publisherContainer[m_publisherIndex]; + auto publisher = m_publisherContainer.iter_from_index(m_publisherIndex); // disconnect publisher from all its subscribers - for (auto& pair : publisher.connectionMap) + for (auto& pair : publisher->connectionMap) { - pair.second->publisherInfo = nullptr; // publisher is disconnected - pair.second->state = ConnectionState::DEFAULT; // connection state is now default + auto connIter = m_connectionContainer.iter_from_index(pair.second); + if (connIter != m_connectionContainer.end()) + { + connIter->publisherInfoIndex.reset(); // publisher is disconnected + connIter->state = ConnectionState::DEFAULT; // connection state is now default + } } innerPublisherMap.erase(iterInnerMap); - m_publisherContainer.remove(m_publisherIndex); + m_publisherContainer.erase(publisher); setNew(true); // indicates we have to send new data because // something changed @@ -404,20 +413,24 @@ PortIntrospection::PortData::removeSubscriber(con // remove subscriber in corresponding publisher auto connectionIndex = mapIter->second; - auto& connection = m_connectionContainer[connectionIndex]; - auto& publisher = connection.publisherInfo; + auto connection = m_connectionContainer.iter_from_index(connectionIndex); + auto publisherInfoIndex = connection->publisherInfoIndex; - if (publisher) + if (publisherInfoIndex.has_value()) { - auto connIter = publisher->connectionMap.find(connectionIndex); - if (connIter != publisher->connectionMap.end()) + auto publisherInfo = m_publisherContainer.iter_from_index(publisherInfoIndex.value()); + if (publisherInfo != m_publisherContainer.end()) { - publisher->connectionMap.erase(connIter); + auto connIter = publisherInfo->connectionMap.find(connectionIndex); + if (connIter != publisherInfo->connectionMap.end()) + { + publisherInfo->connectionMap.erase(connIter); + } } } innerConnectionMap.erase(mapIter); - m_connectionContainer.remove(connectionIndex); + m_connectionContainer.erase(connection); setNew(true); return true; @@ -533,20 +546,20 @@ PortIntrospection::PortData::prepareTopic(PortInt auto m_publisherIndex = pair.second; if (m_publisherIndex >= 0) { - auto& publisherInfo = m_publisherContainer[m_publisherIndex]; + auto publisherInfo = m_publisherContainer.iter_from_index(m_publisherIndex); PublisherPortData publisherData; - PublisherPort port(publisherInfo.portData); + PublisherPort port(publisherInfo->portData); publisherData.m_publisherPortID = static_cast(port.getUniqueID()); - publisherData.m_sourceInterface = publisherInfo.service.getSourceInterface(); - publisherData.m_name = publisherInfo.process; - publisherData.m_node = publisherInfo.node; + publisherData.m_sourceInterface = publisherInfo->service.getSourceInterface(); + publisherData.m_name = publisherInfo->process; + publisherData.m_node = publisherInfo->node; - publisherData.m_caproInstanceID = publisherInfo.service.getInstanceIDString(); - publisherData.m_caproServiceID = publisherInfo.service.getServiceIDString(); - publisherData.m_caproEventMethodID = publisherInfo.service.getEventIDString(); + publisherData.m_caproInstanceID = publisherInfo->service.getInstanceIDString(); + publisherData.m_caproServiceID = publisherInfo->service.getServiceIDString(); + publisherData.m_caproEventMethodID = publisherInfo->service.getEventIDString(); m_publisherList.emplace_back(publisherData); - publisherInfo.index = index++; + publisherInfo->index = index++; } } } @@ -559,9 +572,9 @@ PortIntrospection::PortData::prepareTopic(PortInt auto connectionIndex = pair.second; if (connectionIndex >= 0) { - auto& connection = m_connectionContainer[connectionIndex]; + auto connection = m_connectionContainer.iter_from_index(connectionIndex); SubscriberPortData subscriberData; - auto& subscriberInfo = connection.subscriberInfo; + auto& subscriberInfo = connection->subscriberInfo; subscriberData.m_name = subscriberInfo.process; subscriberData.m_node = subscriberInfo.node; @@ -597,8 +610,8 @@ inline void PortIntrospection::PortData::prepareT auto connectionIndex = pair.second; if (connectionIndex >= 0) { - auto& connection = m_connectionContainer[connectionIndex]; - auto& subscriberInfo = connection.subscriberInfo; + auto connection = m_connectionContainer.iter_from_index(connectionIndex); + auto& subscriberInfo = connection->subscriberInfo; SubscriberPortChangingData subscriberData; if (subscriberInfo.portData != nullptr) { diff --git a/iceoryx_posh/test/moduletests/test_fixed_size_container.cpp b/iceoryx_posh/test/moduletests/test_fixed_size_container.cpp deleted file mode 100644 index 5858e1f48f6..00000000000 --- a/iceoryx_posh/test/moduletests/test_fixed_size_container.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved. -// Copyright (c) 2021 by Apex.AI Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 - -#include "iceoryx_posh/internal/roudi/introspection/fixed_size_container.hpp" -#include "test.hpp" - -#include - -namespace -{ -using namespace ::testing; - -using namespace iox::roudi; - -class FixedSizeContainer_test : public Test -{ - public: - using index_t = int32_t; - int32_t NOT_AN_ELEMENT = -1; - FixedSizeContainer_test() - { - } - ~FixedSizeContainer_test() - { - } - - void SetUp() override - { - } - - void TearDown() override - { - } -}; - -TEST_F(FixedSizeContainer_test, addSingleElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "07b8892c-947e-40a8-aaed-a24dacdc2850"); - FixedSizeContainer container; - EXPECT_THAT(container.add(12), Ne(NOT_AN_ELEMENT)); - EXPECT_THAT(container.add(12), Eq(NOT_AN_ELEMENT)); -} - -TEST_F(FixedSizeContainer_test, addMultiElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "78024408-52e1-41ea-8b0a-7cfefe516cb1"); - constexpr uint32_t capacity = 123; - FixedSizeContainer container; - for (uint32_t k = 0; k < capacity; ++k) - { - EXPECT_THAT(container.add(12), Ne(NOT_AN_ELEMENT)); - } - - for (uint32_t k = 0; k < capacity; ++k) - { - EXPECT_THAT(container.add(12), Eq(NOT_AN_ELEMENT)); - } -} - -TEST_F(FixedSizeContainer_test, removeAndSizeSingleElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "614bd693-7427-4557-90a3-5dbcf6ea7ff6"); - FixedSizeContainer container; - EXPECT_THAT(container.size(), Eq(0u)); - container.remove(0); - EXPECT_THAT(container.size(), Eq(0u)); - - EXPECT_THAT(container.add(123), Ne(NOT_AN_ELEMENT)); - EXPECT_THAT(container.size(), Eq(1u)); - EXPECT_THAT(container.add(123), Eq(NOT_AN_ELEMENT)); - EXPECT_THAT(container.size(), Eq(1u)); - EXPECT_THAT(container.add(123), Eq(NOT_AN_ELEMENT)); - EXPECT_THAT(container.size(), Eq(1u)); - - container.remove(0); - EXPECT_THAT(container.size(), Eq(0u)); - container.remove(0); - EXPECT_THAT(container.size(), Eq(0u)); - - EXPECT_THAT(container.add(123), Ne(NOT_AN_ELEMENT)); - EXPECT_THAT(container.size(), Eq(1u)); -} - -TEST_F(FixedSizeContainer_test, removeAndSizeMultiElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "20a93c9c-7c80-494a-a85d-6313efe2f99e"); - constexpr uint32_t capacity = 100; - FixedSizeContainer container; - - for (uint32_t k = 0; k < capacity; ++k) - { - EXPECT_THAT(container.add(12), Ne(NOT_AN_ELEMENT)); - EXPECT_THAT(container.size(), Eq(k + 1)); - } - - for (uint32_t k = 0; k < capacity; ++k) - { - container.remove(static_cast(k)); - EXPECT_THAT(container.size(), Eq(capacity - k - 1)); - } - - for (uint32_t k = 0; k < capacity; ++k) - { - container.add(12); - container.add(12); - container.remove(static_cast(k)); - container.add(12); - - size_t newSize = 2 * (k + 1); - if (newSize > 100) - { - newSize = 100; - } - - EXPECT_THAT(container.size(), Eq(newSize)); - } - - for (uint32_t k = 0; k < capacity; ++k) - { - container.remove(static_cast(k)); - EXPECT_THAT(container.size(), Eq(capacity - k - 1)); - } -} - -TEST_F(FixedSizeContainer_test, addAndVerifySingleElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "c0dabbf3-6d68-4596-9819-1de011fbe272"); - FixedSizeContainer container; - - EXPECT_THAT(container.get(0), Eq(nullptr)); - container.add(1337); - EXPECT_THAT(*container.get(0), Eq(1337)); - EXPECT_THAT(container[0], Eq(1337)); - container.add(42); - EXPECT_THAT(*container.get(0), Eq(1337)); -} - -TEST_F(FixedSizeContainer_test, addAndVerifyMultiElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "de654427-1873-4583-b6a6-117869ca86f0"); - constexpr uint32_t capacity = 25; - FixedSizeContainer container; - - for (uint32_t i = 0; i < capacity; ++i) - { - for (uint32_t k = i; k < capacity; ++k) - { - EXPECT_THAT(container.get(static_cast(k)), Eq(nullptr)); - } - - container.add(2 * i + 1); - - for (uint32_t k = 0; k < i; ++k) - { - EXPECT_THAT(*container.get(static_cast(k)), Eq(2 * k + 1)); - EXPECT_THAT(container[static_cast(k)], Eq(2 * k + 1)); - } - } -} - -TEST_F(FixedSizeContainer_test, removeAndVerifySingleElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "221a8117-673c-445e-b1fa-88fe2117d440"); - FixedSizeContainer container; - - EXPECT_THAT(container.get(0), Eq(nullptr)); - container.add(1337); - EXPECT_THAT(*container.get(0), Eq(1337)); - container.remove(0); - EXPECT_THAT(container.get(0), Eq(nullptr)); -} - -TEST_F(FixedSizeContainer_test, removeAndVerifyMultiElementContainer) -{ - ::testing::Test::RecordProperty("TEST_ID", "ad112c45-1166-41f9-8cd0-af604677957f"); - constexpr uint32_t capacity = 25; - FixedSizeContainer container; - for (uint32_t i = 0; i < capacity; ++i) - { - container.add(5 * i + 12); - } - - for (uint32_t i = 0; i < capacity; ++i) - { - for (uint32_t k = 0; k < i; ++k) - { - EXPECT_THAT(container.get(static_cast(k)), Eq(nullptr)); - } - container.remove(static_cast(i)); - for (uint32_t k = i + 1; k < capacity; ++k) - { - EXPECT_THAT(*container.get(static_cast(k)), Eq(5 * k + 12)); - } - } -} - -} // namespace