|
| 1 | +/** |
| 2 | + * \file topPorts.hpp |
| 3 | + * \brief Template class implementing the most popular ports. |
| 4 | + * \author Damir Zainullin <[email protected]> |
| 5 | + * \date 2024 |
| 6 | + */ |
| 7 | +#pragma once |
| 8 | + |
| 9 | +#include <array> |
| 10 | +#include <cmath> |
| 11 | +#include <cstdint> |
| 12 | +#include <functional> |
| 13 | +#include <limits> |
| 14 | +#include <queue> |
| 15 | +#include <unordered_map> |
| 16 | +#include <unordered_set> |
| 17 | + |
| 18 | +namespace ipxp { |
| 19 | +/** |
| 20 | + * \brief Top ports counter. |
| 21 | + * \tparam TopPortsCount Number of the most popular ports to store. |
| 22 | + */ |
| 23 | +template<std::size_t TopPortsCount> |
| 24 | +class TopPorts { |
| 25 | +public: |
| 26 | + /** |
| 27 | + * \brief Insert a port into the top ports. |
| 28 | + * \param port Port to insert. |
| 29 | + */ |
| 30 | + void insert(uint16_t port) noexcept |
| 31 | + { |
| 32 | + m_port_frequencies[port]++; |
| 33 | + |
| 34 | + if (m_ports_present.size() < TopPortsCount) { |
| 35 | + m_ports_present.insert(port); |
| 36 | + m_least_popuplar_top_port = find_least_popular_top_port(); |
| 37 | + return; |
| 38 | + } |
| 39 | + |
| 40 | + if (auto it = m_ports_present.find(port); it == m_ports_present.end() |
| 41 | + && m_port_frequencies[port] > m_port_frequencies[m_least_popuplar_top_port]) { |
| 42 | + m_ports_present.erase(m_least_popuplar_top_port); |
| 43 | + m_least_popuplar_top_port = port; |
| 44 | + m_ports_present.insert(port); |
| 45 | + } else if (port == m_least_popuplar_top_port) { |
| 46 | + m_least_popuplar_top_port = find_least_popular_top_port(); |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * \brief Get the top ports. |
| 52 | + * \return Pair of the top ports array and their count. |
| 53 | + */ |
| 54 | + std::pair<std::array<std::pair<uint16_t, size_t>, TopPortsCount>, size_t> |
| 55 | + get_top_ports() const noexcept |
| 56 | + { |
| 57 | + std::array<std::pair<uint16_t, size_t>, TopPortsCount> res; |
| 58 | + std::transform( |
| 59 | + m_ports_present.begin(), |
| 60 | + m_ports_present.end(), |
| 61 | + res.begin(), |
| 62 | + [this](uint16_t port) { return std::make_pair(port, m_port_frequencies[port]); }); |
| 63 | + std::sort(res.begin(), res.begin() + m_ports_present.size(), [] (const std::pair<uint16_t, size_t>& port1, const std::pair<uint16_t, size_t>& port2){ return port1.second > port2.second;}); |
| 64 | + return {res, m_ports_present.size()}; |
| 65 | + } |
| 66 | + |
| 67 | +private: |
| 68 | + uint16_t find_least_popular_top_port() const noexcept |
| 69 | + { |
| 70 | + return *std::min_element( |
| 71 | + m_ports_present.begin(), |
| 72 | + m_ports_present.end(), |
| 73 | + [this](uint16_t port1, uint16_t port2) { |
| 74 | + return m_port_frequencies[port1] < m_port_frequencies[port2]; |
| 75 | + }); |
| 76 | + } |
| 77 | + |
| 78 | + std::array<std::size_t, 65536> m_port_frequencies {}; |
| 79 | + uint16_t m_least_popuplar_top_port {0}; |
| 80 | + std::unordered_set<uint16_t> m_ports_present; |
| 81 | +}; |
| 82 | + |
| 83 | +} // namespace ipxp |
0 commit comments