7#if !defined(ASYNC_MQTT_TOPIC_ALIAS_SEND_HPP)
8#define ASYNC_MQTT_TOPIC_ALIAS_SEND_HPP
11#include <unordered_map>
14#include <boost/assert.hpp>
15#include <boost/multi_index_container.hpp>
16#include <boost/multi_index/ordered_index.hpp>
17#include <boost/multi_index/key.hpp>
19#include <async_mqtt/constant.hpp>
20#include <async_mqtt/log.hpp>
21#include <async_mqtt/util/move.hpp>
22#include <async_mqtt/util/optional.hpp>
23#include <async_mqtt/util/value_allocator.hpp>
24#include <async_mqtt/util/time_point.hpp>
25#include <async_mqtt/util/string_view.hpp>
29namespace mi = boost::multi_index;
31class topic_alias_send {
33 topic_alias_send(topic_alias_t max)
34 :max_{max}, va_{min_, max_} {}
36 void insert_or_update(string_view topic, topic_alias_t alias) {
37 ASYNC_MQTT_LOG(
"mqtt_impl", trace)
38 << ASYNC_MQTT_ADD_VALUE(address,
this)
39 <<
"topic_alias_send insert"
41 <<
" alias:" << alias;
42 BOOST_ASSERT(!topic.empty() && alias >= min_ && alias <= max_);
44 auto& idx = aliases_.get<tag_alias>();
45 auto it = idx.lower_bound(alias);
46 if (it == idx.end() || it->alias != alias) {
47 idx.emplace_hint(it, std::string(topic), alias, std::chrono::steady_clock::now());
53 e.topic = std::string{topic};
54 e.tp = std::chrono::steady_clock::now();
56 [](
auto&) { BOOST_ASSERT(
false); }
62 std::string find(topic_alias_t alias) {
63 ASYNC_MQTT_LOG(
"mqtt_impl", trace)
64 << ASYNC_MQTT_ADD_VALUE(address,
this)
65 <<
"find_topic_by_alias"
66 <<
" alias:" << alias;
68 BOOST_ASSERT(alias >= min_ && alias <= max_);
69 auto& idx = aliases_.get<tag_alias>();
70 auto it = idx.find(alias);
71 if (it == idx.end())
return std::string();
76 e.tp = std::chrono::steady_clock::now();
78 [](
auto&) { BOOST_ASSERT(
false); }
83 std::string find_without_touch(topic_alias_t alias)
const {
84 ASYNC_MQTT_LOG(
"mqtt_impl", trace)
85 << ASYNC_MQTT_ADD_VALUE(address,
this)
86 <<
"find_topic_by_alias"
87 <<
" alias:" << alias;
89 BOOST_ASSERT(alias >= min_ && alias <= max_);
90 auto& idx = aliases_.get<tag_alias>();
91 auto it = idx.find(alias);
92 if (it == idx.end())
return std::string();
96 optional<topic_alias_t> find(string_view topic)
const {
97 ASYNC_MQTT_LOG(
"mqtt_impl", trace)
98 << ASYNC_MQTT_ADD_VALUE(address,
this)
99 <<
"find_alias_by_topic"
100 <<
" topic:" << topic;
102 auto& idx = aliases_.get<tag_topic_name>();
103 auto it = idx.find(topic);
104 if (it == idx.end())
return nullopt;
109 ASYNC_MQTT_LOG(
"mqtt_impl", info)
110 << ASYNC_MQTT_ADD_VALUE(address,
this)
111 <<
"clear_topic_alias";
116 topic_alias_t get_lru_alias()
const {
117 BOOST_ASSERT(max_ > 0);
118 if (
auto alias_opt = va_.first_vacant()) {
121 auto& idx = aliases_.get<tag_tp>();
122 return idx.begin()->alias;
125 topic_alias_t max()
const {
return max_; }
128 static constexpr topic_alias_t min_ = 1;
132 entry(std::string topic, topic_alias_t alias, time_point_t tp)
133 : topic{force_move(topic)}, alias{alias}, tp{force_move(tp)} {}
135 string_view get_topic_as_view()
const {
145 struct tag_topic_name {};
146 using mi_topic_alias = mi::multi_index_container<
151 mi::key<&entry::alias>
154 mi::tag<tag_topic_name>,
155 mi::key<&entry::get_topic_as_view>
157 mi::ordered_non_unique<
164 mi_topic_alias aliases_;
165 value_allocator<topic_alias_t> va_;