Program Listing for File LocatorSelector.hpp

Return to documentation for file (/tmp/ws/src/fastrtps/include/fastdds/rtps/common/LocatorSelector.hpp)

// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// 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.

#ifndef _FASTDDS_RTPS_COMMON_LOCATORSELECTOR_HPP_
#define _FASTDDS_RTPS_COMMON_LOCATORSELECTOR_HPP_

#include <fastdds/rtps/common/LocatorSelectorEntry.hpp>
#include <fastdds/rtps/common/Guid.h>
#include <fastdds/rtps/common/Locator.h>
#include <fastrtps/utils/collections/ResourceLimitedVector.hpp>
#include <fastrtps/utils/IPLocator.h>

#include <algorithm>

namespace eprosima {
namespace fastrtps {
namespace rtps {

class LocatorSelector
{
public:

    LocatorSelector(
            const ResourceLimitedContainerConfig& entries_allocation)
        : entries_(entries_allocation)
        , selections_(entries_allocation)
        , last_state_(entries_allocation)
    {
    }

    void clear()
    {
        entries_.clear();
        selections_.clear();
        last_state_.clear();
    }

    bool add_entry(
            LocatorSelectorEntry* entry)
    {
        return entries_.push_back(entry) != nullptr;
    }

    bool remove_entry(
            const GUID_t& guid)
    {
        return entries_.remove_if(
            [&guid](LocatorSelectorEntry* entry)
            {
                return entry->remote_guid == guid;
            });
    }

    void reset(
            bool enable_all)
    {
        last_state_.clear();
        for (LocatorSelectorEntry* entry : entries_)
        {
            last_state_.push_back(entry->enabled ? 1 : 0);
            entry->enable(enable_all);
        }
    }

    void enable(
            const GUID_t& guid)
    {
        for (LocatorSelectorEntry* entry : entries_)
        {
            if (entry->remote_guid == guid)
            {
                entry->enabled = true;
                break;
            }
        }
    }

    bool state_has_changed() const
    {
        if (entries_.size() != last_state_.size())
        {
            return true;
        }

        for (size_t i = 0; i < entries_.size(); ++i)
        {
            if (last_state_.at(i) != (entries_.at(i)->enabled ? 1 : 0))
            {
                return true;
            }
        }

        return false;
    }

    void selection_start()
    {
        selections_.clear();
        for (LocatorSelectorEntry* entry : entries_)
        {
            entry->reset();
        }
    }

    ResourceLimitedVector<LocatorSelectorEntry*>& transport_starts()
    {
        for (LocatorSelectorEntry* entry : entries_)
        {
            entry->transport_should_process = entry->enabled;
        }

        return entries_;
    }

    void select(
            size_t index)
    {
        if (index < entries_.size() &&
                std::find(selections_.begin(), selections_.end(), index) == selections_.end())
        {
            selections_.push_back(index);
        }
    }

    size_t selected_size() const
    {
        size_t result = 0;

        for (size_t index : selections_)
        {
            LocatorSelectorEntry* entry = entries_.at(index);
            result += entry->state.multicast.size();
            result += entry->state.unicast.size();
        }

        return result;
    }

    bool is_selected(
            const Locator_t locator) const
    {
        if (IPLocator::isMulticast(locator))
        {
            for (size_t index : selections_)
            {
                LocatorSelectorEntry* entry = entries_.at(index);
                for (size_t loc_index : entry->state.multicast)
                {
                    if (entry->multicast.at(loc_index) == locator)
                    {
                        return true;
                    }
                }
            }
        }
        else
        {
            for (size_t index : selections_)
            {
                LocatorSelectorEntry* entry = entries_.at(index);
                for (size_t loc_index : entry->state.unicast)
                {
                    if (entry->unicast.at(loc_index) == locator)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    template<class UnaryPredicate>
    void for_each(
            UnaryPredicate action) const
    {
        for (size_t index : selections_)
        {
            LocatorSelectorEntry* entry = entries_.at(index);
            for (size_t loc_index : entry->state.multicast)
            {
                action(entry->multicast.at(loc_index));
            }
            for (size_t loc_index : entry->state.unicast)
            {
                action(entry->unicast.at(loc_index));
            }
        }
    }

    struct IteratorIndex
    {
        size_t selections_index;
        size_t state_index;
        bool state_multicast_done;
        Locator_t* locator;
    };

    class iterator :
        public LocatorsIterator
    {
        // use of std::iterator to introduce the following aliases is deprecated
        using iterator_category = std::input_iterator_tag;
        using value_type        = Locator_t;
        using difference_type   = IteratorIndex;
        using pointer           = Locator_t*;
        using reference         = Locator_t&;

        const LocatorSelector& locator_selector_;
        IteratorIndex current_;

        void go_to_next_entry()
        {
            // While entries selected
            while (++current_.selections_index < locator_selector_.selections_.size())
            {
                LocatorSelectorEntry* entry =
                        locator_selector_.entries_.at(locator_selector_.selections_[current_.selections_index]);

                // No multicast locators in this entry
                if (entry->state.multicast.size() == 0)
                {
                    // But there's unicast
                    if (entry->state.unicast.size() > 0)
                    {
                        current_.locator = &entry->unicast[entry->state.unicast.at(0)];
                        return;
                    }
                }
                else     // process multicast
                {
                    current_.state_multicast_done = false;
                    current_.locator = &entry->multicast[entry->state.multicast.at(0)];
                    return;
                }
            }

            current_.locator = nullptr;
        }

    public:

        enum class Position
        {
            Begin,
            End
        };

        explicit iterator(
                const LocatorSelector& locator_selector,
                Position index_pos)
            : locator_selector_(locator_selector)
        {
            current_ = {(std::numeric_limits<size_t>::max)(), 0, true, nullptr};

            if (index_pos == Position::Begin)
            {
                go_to_next_entry();
            }
        }

        iterator(
                const iterator& other)
            : locator_selector_(other.locator_selector_)
            , current_(other.current_)
        {
        }

        iterator& operator ++()
        {
            // Shouldn't call ++ when index already at the end
            assert(current_.selections_index < locator_selector_.selections_.size());

            LocatorSelectorEntry* entry =
                    locator_selector_.entries_.at(locator_selector_.selections_[current_.selections_index]);

            // Index at unicast locators
            if (current_.state_multicast_done)
            {
                // No more unicast locators selected
                if (++current_.state_index >= entry->state.unicast.size())
                {
                    current_.state_index = 0;
                    go_to_next_entry();
                }
                else     // current unicast locator
                {
                    current_.locator = &entry->unicast[entry->state.unicast.at(current_.state_index)];
                }
            }
            else     // Index at multicast locators
            {
                // No more multicast locators selected
                if (++current_.state_index >= entry->state.multicast.size())
                {
                    // Reset index to process unicast
                    current_.state_multicast_done = true;
                    current_.state_index = 0;
                    // No unicast locators
                    if (current_.state_index >= entry->state.unicast.size())
                    {
                        go_to_next_entry();
                    }
                    else     // current unicast locator
                    {
                        current_.locator = &entry->unicast[entry->state.unicast.at(current_.state_index)];
                    }
                }
                else     // current multicast locator
                {
                    current_.locator = &entry->multicast[entry->state.multicast.at(current_.state_index)];
                }
            }

            return *this;
        }

        bool operator ==(
                const LocatorsIterator& other) const
        {
            return *this == static_cast<const iterator&>(other);
        }

        bool operator !=(
                const LocatorsIterator& other) const
        {
            return !(*this == other);
        }

        bool operator ==(
                const iterator& other) const
        {
            return (current_.locator == other.current_.locator);
        }

        bool operator !=(
                const iterator& other) const
        {
            return !(*this == other);
        }

        pointer operator ->() const
        {
            return current_.locator;
        }

        reference operator *() const
        {
            return *current_.locator;
        }

    };

    iterator begin() const
    {
        return iterator(*this, iterator::Position::Begin);
    }

    iterator end() const
    {
        return iterator(*this, iterator::Position::End);
    }

private:

    ResourceLimitedVector<LocatorSelectorEntry*> entries_;
    ResourceLimitedVector<size_t> selections_;
    ResourceLimitedVector<int> last_state_;
};

} /* namespace rtps */
} /* namespace fastrtps */
} /* namespace eprosima */

#endif /* _FASTDDS_RTPS_COMMON_LOCATORSELECTOR_H_ */