async_mqtt 5.0.0
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_TOPIC_ALIAS_SEND_HPP)
8#define ASYNC_MQTT_TOPIC_ALIAS_SEND_HPP
9
10#include <string>
11#include <unordered_map>
12#include <array>
13
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>
18
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>
26
27namespace async_mqtt {
28
29namespace mi = boost::multi_index;
30
31class topic_alias_send {
32public:
33 topic_alias_send(topic_alias_t max)
34 :max_{max}, va_{min_, max_} {}
35
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"
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
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;
67
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();
72
73 idx.modify(
74 it,
75 [&](entry& e) {
76 e.tp = std::chrono::steady_clock::now();
77 },
78 [](auto&) { BOOST_ASSERT(false); }
79 );
80 return it->topic;
81 }
82
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;
88
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();
93 return it->topic;
94 }
95
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;
101
102 auto& idx = aliases_.get<tag_topic_name>();
103 auto it = idx.find(topic);
104 if (it == idx.end()) return nullopt;
105 return it->alias;
106 }
107
108 void clear() {
109 ASYNC_MQTT_LOG("mqtt_impl", info)
110 << ASYNC_MQTT_ADD_VALUE(address, this)
111 << "clear_topic_alias";
112 aliases_.clear();
113 va_.clear();
114 }
115
116 topic_alias_t get_lru_alias() const {
117 BOOST_ASSERT(max_ > 0);
118 if (auto alias_opt = va_.first_vacant()) {
119 return *alias_opt;
120 }
121 auto& idx = aliases_.get<tag_tp>();
122 return idx.begin()->alias;
123 }
124
125 topic_alias_t max() const { return max_; }
126
127private:
128 static constexpr topic_alias_t min_ = 1;
129 topic_alias_t max_;
130
131 struct entry {
132 entry(std::string topic, topic_alias_t alias, time_point_t tp)
133 : topic{force_move(topic)}, alias{alias}, tp{force_move(tp)} {}
134
135 string_view get_topic_as_view() const {
136 return topic;
137 }
138
139 std::string topic;
140 topic_alias_t alias;
141 time_point_t tp;
142 };
143 struct tag_tp {};
144 struct tag_alias {};
145 struct tag_topic_name {};
146 using mi_topic_alias = mi::multi_index_container<
147 entry,
148 mi::indexed_by<
149 mi::ordered_unique<
150 mi::tag<tag_alias>,
151 mi::key<&entry::alias>
152 >,
153 mi::ordered_unique<
154 mi::tag<tag_topic_name>,
155 mi::key<&entry::get_topic_as_view>
156 >,
157 mi::ordered_non_unique<
158 mi::tag<tag_tp>,
159 mi::key<&entry::tp>
160 >
161 >
162 >;
163
164 mi_topic_alias aliases_;
165 value_allocator<topic_alias_t> va_;
166};
167
168} // namespace async_mqtt
169
170#endif // ASYNC_MQTT_TOPIC_ALIAS_SEND_HPP