async_mqtt 9.0.1
Loading...
Searching...
No Matches
topic_alias_send.hpp
1// Copyright Takatoshi Kondo 2020
2//
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#if !defined(ASYNC_MQTT_UTIL_TOPIC_ALIAS_SEND_HPP)
8#define ASYNC_MQTT_UTIL_TOPIC_ALIAS_SEND_HPP
9
10#include <string>
11#include <string_view>
12#include <unordered_map>
13#include <array>
14#include <chrono>
15#include <optional>
16
17#include <boost/assert.hpp>
18#include <boost/multi_index_container.hpp>
19#include <boost/multi_index/ordered_index.hpp>
20#include <boost/multi_index/key.hpp>
21
22#include <async_mqtt/util/log.hpp>
23#include <async_mqtt/util/move.hpp>
24#include <async_mqtt/util/value_allocator.hpp>
25#include <async_mqtt/packet/property.hpp>
26
27namespace async_mqtt {
28
29namespace mi = boost::multi_index;
30
31class topic_alias_send {
32public:
33 explicit topic_alias_send(topic_alias_type max)
34 :max_{max}, va_{min_, max_} {}
35
36 void insert_or_update(std::string_view topic, topic_alias_type alias) {
37 ASYNC_MQTT_LOG("mqtt_impl", trace)
38 << ASYNC_MQTT_ADD_VALUE(address, this)
39 << "topic_alias_send insert"
40 << " topic:" << topic
41 << " alias:" << alias;
42 BOOST_ASSERT(!topic.empty() && alias >= min_ && alias <= max_);
43 va_.use(alias);
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());
48 }
49 else {
50 idx.modify(
51 it,
52 [&](entry& e) {
53 e.topic = std::string{topic};
54 e.tp = std::chrono::steady_clock::now();
55 },
56 [](auto&) { BOOST_ASSERT(false); }
57 );
58 }
59 }
60
61 std::string find(topic_alias_type alias) {
62 ASYNC_MQTT_LOG("mqtt_impl", trace)
63 << ASYNC_MQTT_ADD_VALUE(address, this)
64 << "find_topic_by_alias"
65 << " alias:" << alias;
66
67 if (alias >= min_ && alias <= max_) {
68 auto& idx = aliases_.get<tag_alias>();
69 auto it = idx.find(alias);
70 if (it == idx.end()) return std::string();
71
72 idx.modify(
73 it,
74 [&](entry& e) {
75 e.tp = std::chrono::steady_clock::now();
76 },
77 [](auto&) { BOOST_ASSERT(false); }
78 );
79 return it->topic;
80 }
81 return std::string{};
82 }
83
84 std::string find_without_touch(topic_alias_type alias) const {
85 ASYNC_MQTT_LOG("mqtt_impl", trace)
86 << ASYNC_MQTT_ADD_VALUE(address, this)
87 << "find_topic_by_alias"
88 << " alias:" << alias;
89
90 if (alias >= min_ && alias <= max_) {
91 auto& idx = aliases_.get<tag_alias>();
92 auto it = idx.find(alias);
93 if (it == idx.end()) return std::string();
94 return it->topic;
95 }
96 return std::string{};
97 }
98
99 std::optional<topic_alias_type> find(std::string_view topic) const {
100 ASYNC_MQTT_LOG("mqtt_impl", trace)
101 << ASYNC_MQTT_ADD_VALUE(address, this)
102 << "find_alias_by_topic"
103 << " topic:" << topic;
104
105 auto& idx = aliases_.get<tag_topic_name>();
106 auto it = idx.find(topic);
107 if (it == idx.end()) return std::nullopt;
108 return it->alias;
109 }
110
111 void clear() {
112 ASYNC_MQTT_LOG("mqtt_impl", info)
113 << ASYNC_MQTT_ADD_VALUE(address, this)
114 << "clear_topic_alias";
115 aliases_.clear();
116 va_.clear();
117 }
118
119 topic_alias_type get_lru_alias() const {
120 BOOST_ASSERT(max_ > 0);
121 if (auto alias_opt = va_.first_vacant()) {
122 return *alias_opt;
123 }
124 auto& idx = aliases_.get<tag_tp>();
125 return idx.begin()->alias;
126 }
127
128 topic_alias_type max() const { return max_; }
129
130private:
131 static constexpr topic_alias_type min_ = 1;
132 topic_alias_type max_;
133
134 struct entry {
135 entry(std::string topic, topic_alias_type alias, std::chrono::time_point<std::chrono::steady_clock> tp)
136 : topic{force_move(topic)}, alias{alias}, tp{force_move(tp)} {}
137
138 std::string_view get_topic_as_view() const {
139 return topic;
140 }
141
142 std::string topic;
143 topic_alias_type alias;
144 std::chrono::time_point<std::chrono::steady_clock> tp;
145 };
146 struct tag_tp {};
147 struct tag_alias {};
148 struct tag_topic_name {};
149 using mi_topic_alias = mi::multi_index_container<
150 entry,
151 mi::indexed_by<
152 mi::ordered_unique<
153 mi::tag<tag_alias>,
154 mi::key<&entry::alias>
155 >,
156 mi::ordered_unique<
157 mi::tag<tag_topic_name>,
158 mi::key<&entry::get_topic_as_view>
159 >,
160 mi::ordered_non_unique<
161 mi::tag<tag_tp>,
162 mi::key<&entry::tp>
163 >
164 >
165 >;
166
167 mi_topic_alias aliases_;
168 value_allocator<topic_alias_type> va_;
169};
170
171} // namespace async_mqtt
172
173#endif // ASYNC_MQTT_UTIL_TOPIC_ALIAS_SEND_HPP
@ trace
trace level for detaied behavior and reporting issue
@ info
info level api call is output
std::uint16_t topic_alias_type
type of the topic alias value
Definition property.hpp:81